public override void VisitBinaryOperatorExpression <TExpression>(
     IBinaryOperatorExpression <TExpression> binaryOperatorExpression)
 {
     Value = new Expression()
     {
         BinaryOperatorExpression = new BinaryOperatorExpressionFactory(binaryOperatorExpression).Value
     };
 }
        public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
        {
            var usesOperatorMethod  = operation.UsesOperatorMethod;
            var operatorMethod      = operation.OperatorMethod;
            var binaryOperationKind = operation.BinaryOperationKind;

            base.VisitBinaryOperatorExpression(operation);
        }
 public static void VisitBinaryOperatorExpressionChildren<TExpression>(
     IBinaryOperatorExpression<TExpression> binaryOperatorExpression,
     IGenericExpressionVisitor visitor)
     where TExpression : IExpression
 {
     VisitIfNotNull(binaryOperatorExpression.Left, visitor);
     VisitIfNotNull(binaryOperatorExpression.Right, visitor);
 }
 public override void VisitBinaryOperatorExpression <TExpression>(
     IBinaryOperatorExpression <TExpression> binaryOperatorExpression)
 {
     Steps.Add(new WriteExpression <TExpression>(binaryOperatorExpression.Left));
     Steps.Add(new WriteWhitespace());
     Steps.Add(new WriteBinaryOperatorExpressionType(binaryOperatorExpression.OperatorType));
     Steps.Add(new WriteWhitespace());
     Steps.Add(new WriteExpression <TExpression>(binaryOperatorExpression.Right));
 }
Exemple #5
0
        public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
        {
            var operatorMethod      = operation.OperatorMethod;
            var binaryOperationKind = operation.OperatorKind;
            var isLifted            = operation.IsLifted;
            var isChecked           = operation.IsChecked;
            var isCompareText       = operation.IsCompareText;

            base.VisitBinaryOperatorExpression(operation);
        }
        /// <summary>
        /// Compares two expressions.
        /// </summary>
        /// <param name="other">The other expression.</param>
        protected bool IsExpressionEqual(IBinaryOperatorExpression other)
        {
            Debug.Assert(other != null);

            bool Result = true;

            Result &= Expression.IsExpressionEqual((IExpression)LeftExpression, (IExpression)other.LeftExpression);
            Result &= Operator.Text == other.Operator.Text;
            Result &= Expression.IsExpressionEqual((IExpression)RightExpression, (IExpression)other.RightExpression);

            return(Result);
        }
Exemple #7
0
 private static void AnalyzeBinaryExpression(IBinaryOperatorExpression operation, Action <Diagnostic> reportDiagnostic, Func <SyntaxNode, Location> getOperatorTokenLocation)
 {
     if (operation.BinaryOperationKind == BinaryOperationKind.StringEquals || operation.BinaryOperationKind == BinaryOperationKind.StringNotEquals)
     {
         // If either of the operands is null, we shouldn't report a diagnostic.
         if (operation.LeftOperand.HasNullConstantValue() || operation.RightOperand.HasNullConstantValue())
         {
             return;
         }
         reportDiagnostic(Diagnostic.Create(Rule, getOperatorTokenLocation(operation.Syntax)));
     }
 }
 private static void AnalyzeBinaryExpression(IBinaryOperatorExpression operation, Action<Diagnostic> reportDiagnostic, Func<SyntaxNode, Location> getOperatorTokenLocation)
 {
     if (operation.BinaryOperationKind == BinaryOperationKind.StringEquals || operation.BinaryOperationKind == BinaryOperationKind.StringNotEquals)
     {
         // If either of the operands is null, we shouldn't report a diagnostic.
         if (operation.LeftOperand.HasNullConstantValue() || operation.RightOperand.HasNullConstantValue())
         {
             return;
         }
         reportDiagnostic(Diagnostic.Create(Rule, getOperatorTokenLocation(operation.Syntax)));
     }
 }
        public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
        {
            LogString(nameof(IBinaryOperatorExpression));

            var kindStr = $"{nameof(BinaryOperationKind)}.{operation.BinaryOperationKind}";

            LogString($" ({kindStr})");
            LogHasOperatorMethodExpressionCommon(operation);
            LogCommonPropertiesAndNewLine(operation);

            Visit(operation.LeftOperand, "Left");
            Visit(operation.RightOperand, "Right");
        }
 private void AnalyzeBinaryExpression(IBinaryOperatorExpression operation, Action <Diagnostic> reportDiagnostic)
 {
     if (operation.BinaryOperationKind == BinaryOperationKind.StringEquals || operation.BinaryOperationKind == BinaryOperationKind.StringNotEquals)
     {
         // If either of the operands is null, we shouldn't report a diagnostic.
         if ((operation.LeftOperand.ConstantValue.HasValue && operation.LeftOperand.ConstantValue.Value == null) ||
             (operation.RightOperand.ConstantValue.HasValue && operation.RightOperand.ConstantValue.Value == null))
         {
             return;
         }
         reportDiagnostic(Diagnostic.Create(Rule, GetOperatorTokenLocation(operation.Syntax)));
     }
 }
Exemple #11
0
            private string GetExpression(IBinaryOperatorExpression expression, ref List <OleDbParameter> parameters)
            {
                if (expression is ShortcutConditionalOperatorExpression)
                {
                    return(GetExpression(expression as ShortcutConditionalOperatorExpression, ref parameters));
                }

                //    if (expression is DivideExpression)
                //    {
                //        return GetExpression(expression as DivideExpression, ref parameters);
                //    }


                if (expression is ComparisonOperatorExpression)
                {
                    return(GetExpression(expression as ComparisonOperatorExpression, ref parameters));
                }

                if (expression is LikeExpression)
                {
                    return(GetExpression(expression as LikeExpression, ref parameters));
                }
                //    if (expression is MinusExpression)
                //    {
                //        return GetExpression(expression as MinusExpression, ref parameters);
                //    }
                //    if (expression is MultiplyExpression)
                //    {
                //        return GetExpression(expression as MultiplyExpression, ref parameters);
                //    }
                //    if (expression is MinusExpression)
                //    {
                //        return GetExpression(expression as MinusExpression, ref parameters);
                //    }
                //    if (expression is PlusExpression)
                //    {
                //        return GetExpression(expression as PlusExpression, ref parameters);
                //    }

                else
                {
                    return(expression.ToString());
                }
            }
 public virtual void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
 {
     DefaultVisit(operation);
 }
 /// <summary>
 /// Get binary operation kind independent of data type.
 /// </summary>
 public static SimpleBinaryOperationKind GetSimpleBinaryOperationKind(this IBinaryOperatorExpression binary)
 {
     return(GetSimpleBinaryOperationKind(binary.BinaryOperationKind));
 }
Exemple #14
0
 public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
 {
     Visit(operation.LeftOperand);
     Visit(operation.RightOperand);
 }
Exemple #15
0
 public virtual void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
 {
     DefaultVisit(operation);
 }
            private string GetExpression(IBinaryOperatorExpression expression, ref List<OleDbParameter> parameters)
            {
                if (expression is ShortcutConditionalOperatorExpression)
                {
                    return GetExpression(expression as ShortcutConditionalOperatorExpression, ref parameters);
                }

                if (expression is ComparisonOperatorExpression)
                {
                    return GetExpression(expression as ComparisonOperatorExpression, ref parameters);
                }

                if (expression is LikeExpression)
                {
                    return GetExpression(expression as LikeExpression, ref parameters);
                }
                if (expression is DivideExpression)
                {
                    return GetExpression(expression as DivideExpression, ref parameters);
                }
                if (expression is MultiplyExpression)
                {
                    return GetExpression(expression as MultiplyExpression, ref parameters);
                }
                if (expression is MinusExpression)
                {
                    return GetExpression(expression as MinusExpression, ref parameters);
                }
                if (expression is PlusExpression)
                {
                    return GetExpression(expression as PlusExpression, ref parameters);
                }

                else
                    return expression.ToString();
            }
 public static IBinaryOperatorExpression Update(this IBinaryOperatorExpression self, Enum @operatorKind, IOperation @left, IOperation @right, Object @constantValueOpt, IMethodSymbol @methodOpt, Enum @resultKind, ITypeSymbol @type) => self;
 /// <summary>
 /// Get binary operand kinds.
 /// </summary>
 public static BinaryOperandsKind GetBinaryOperandsKind(this IBinaryOperatorExpression binary)
 {
     return(GetBinaryOperandsKind(binary.BinaryOperationKind));
 }
 public virtual void VisitBinaryOperatorExpression <TExpression>(
     IBinaryOperatorExpression <TExpression> binaryOperatorExpression)
     where TExpression : IExpression
 {
     Visit(binaryOperatorExpression);
 }
Exemple #20
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CSharpBinaryOperatorExpression"/> class.
        /// </summary>
        /// <param name="source">The Easly expression from which the C# expression is created.</param>
        /// <param name="context">The creation context.</param>
        protected CSharpBinaryOperatorExpression(ICSharpContext context, IBinaryOperatorExpression source)
            : base(context, source)
        {
            LeftExpression  = Create(context, (IExpression)source.LeftExpression);
            RightExpression = Create(context, (IExpression)source.RightExpression);

            Operator = context.GetFeature(source.SelectedFeature.Item) as ICSharpFunctionFeature;
            Debug.Assert(Operator != null);

            IResultType     ResolvedLeftResult  = LeftExpression.Source.ResolvedResult.Item;
            IExpressionType PreferredLeftResult = ResolvedLeftResult.Preferred;

            Debug.Assert(PreferredLeftResult != null);

            if (PreferredLeftResult.ValueType is IClassType AsClassType)
            {
                if (AsClassType.BaseClass.ClassGuid == LanguageClasses.Number.Guid || AsClassType.BaseClass.ClassGuid == LanguageClasses.Integer.Guid)
                {
                    IsCallingNumberFeature = true;
                }
            }

            if (IsCallingNumberFeature)
            {
                IResultType ResolvedRightResult = RightExpression.Source.ResolvedResult.Item;
                Debug.Assert(ResolvedRightResult.Count == 1);
            }
            else
            {
                if (!LeftExpression.IsSingleResult)
                {
                    IResultType LeftResultType = LeftExpression.Source.ResolvedResult.Item;
                    LeftNameList        = new List <string>();
                    LeftResultNameIndex = LeftResultType.ResultNameIndex;

                    for (int i = 0; i < LeftResultType.Count; i++)
                    {
                        IExpressionType DestinationType = LeftResultType.At(i);
                        string          Text            = DestinationType.Name;
                        LeftNameList.Add(Text);
                    }
                }

                if (!RightExpression.IsSingleResult)
                {
                    IResultType RightResultType = RightExpression.Source.ResolvedResult.Item;
                    RightNameList        = new List <string>();
                    RightResultNameIndex = RightResultType.ResultNameIndex;

                    for (int i = 0; i < RightResultType.Count; i++)
                    {
                        IExpressionType DestinationType = RightResultType.At(i);
                        string          Text            = DestinationType.Name;
                        RightNameList.Add(Text);
                    }
                }
            }

            FeatureCall = new CSharpFeatureCall(context, Source.FeatureCall.Item);

            Debug.Assert(Source.SelectedOverload.IsAssigned);
            IQueryOverload     Overload = Source.SelectedOverload.Item;
            IQueryOverloadType ResolvedAssociatedType = Overload.ResolvedAssociatedType.Item;

            SelectedOverloadType = CSharpQueryOverloadType.Create(context, ResolvedAssociatedType, Operator.Owner);
        }
 /// <inheritdoc />
 public override IOperation VisitBinaryOperatorExpression(IBinaryOperatorExpression operation, object argument)
 {
     return(base.VisitBinaryOperatorExpression(operation, argument));
 }
Exemple #22
0
 /// <summary>
 /// Creates a new C# expression.
 /// </summary>
 /// <param name="context">The creation context.</param>
 /// <param name="source">The Easly expression from which the C# expression is created.</param>
 public static ICSharpBinaryOperatorExpression Create(ICSharpContext context, IBinaryOperatorExpression source)
 {
     return(new CSharpBinaryOperatorExpression(context, source));
 }
 private void AnalyzeBinaryExpression(IBinaryOperatorExpression operation, Action<Diagnostic> reportDiagnostic)
 {
     if (operation.BinaryOperationKind == BinaryOperationKind.StringEquals || operation.BinaryOperationKind == BinaryOperationKind.StringNotEquals)
     {
         // If either of the operands is null, we shouldn't report a diagnostic.
         if ((operation.LeftOperand.ConstantValue.HasValue && operation.LeftOperand.ConstantValue.Value == null) ||
             (operation.RightOperand.ConstantValue.HasValue && operation.RightOperand.ConstantValue.Value == null))
         {
             return;
         }
         reportDiagnostic(Diagnostic.Create(Rule, GetOperatorTokenLocation(operation.Syntax)));
     }
 }
Exemple #24
0
        public override void VisitBinaryOperatorExpression(IBinaryOperatorExpression operation)
        {
            var usesOperatorMethod = operation.UsesOperatorMethod;
            var operatorMethod = operation.OperatorMethod;
            var binaryOperationKind = operation.BinaryOperationKind;

            base.VisitBinaryOperatorExpression(operation);
        }
        /// <summary>
        /// Finds the matching nodes of a <see cref="IBinaryOperatorExpression"/>.
        /// </summary>
        /// <param name="node">The agent expression to check.</param>
        /// <param name="errorList">The list of errors found.</param>
        /// <param name="resolvedResult">The expression result types upon return.</param>
        /// <param name="resolvedException">Exceptions the expression can throw upon return.</param>
        /// <param name="constantSourceList">Sources of the constant expression upon return, if any.</param>
        /// <param name="expressionConstant">The constant value upon return, if any.</param>
        /// <param name="selectedFeature">The matching feature upon return.</param>
        /// <param name="selectedOverload">The matching overload in <paramref name="selectedFeature"/> upon return.</param>
        /// <param name="featureCall">Details of the feature call.</param>
        public static bool ResolveCompilerReferences(IBinaryOperatorExpression node, IErrorList errorList, out IResultType resolvedResult, out IResultException resolvedException, out ISealableList <IExpression> constantSourceList, out ILanguageConstant expressionConstant, out IFunctionFeature selectedFeature, out IQueryOverload selectedOverload, out IFeatureCall featureCall)
        {
            resolvedResult     = null;
            resolvedException  = null;
            constantSourceList = new SealableList <IExpression>();
            expressionConstant = NeutralLanguageConstant.NotConstant;
            selectedFeature    = null;
            selectedOverload   = null;
            featureCall        = null;

            IExpression LeftExpression  = (IExpression)node.LeftExpression;
            IIdentifier Operator        = (IIdentifier)node.Operator;
            IExpression RightExpression = (IExpression)node.RightExpression;
            IResultType LeftResult      = LeftExpression.ResolvedResult.Item;

            if (LeftResult.TryGetResult(out ICompiledType LeftExpressionType))
            {
                if (LeftExpressionType is IClassType AsClassType)
                {
                    string OperatorName = Operator.ValidText.Item;

                    ISealableDictionary <IFeatureName, IFeatureInstance> LeftFeatureTable = AsClassType.FeatureTable;

                    if (!FeatureName.TableContain(LeftFeatureTable, OperatorName, out IFeatureName Key, out IFeatureInstance Value))
                    {
                        errorList.AddError(new ErrorUnknownIdentifier(Operator, OperatorName));
                        return(false);
                    }

                    Debug.Assert(Value.Feature != null);

                    ICompiledFeature OperatorFeature = Value.Feature;
                    ICompiledType    OperatorType    = OperatorFeature.ResolvedAgentType.Item;

                    if (OperatorFeature is IFunctionFeature AsFunctionFeature && OperatorType is FunctionType AsFunctionType)
                    {
                        IList <ISealableList <IParameter> > ParameterTableList = new List <ISealableList <IParameter> >();
                        foreach (IQueryOverloadType Overload in AsFunctionType.OverloadList)
                        {
                            ParameterTableList.Add(Overload.ParameterTable);
                        }

                        IResultType RightResult = RightExpression.ResolvedResult.Item;
                        if (!Argument.ArgumentsConformToParameters(ParameterTableList, RightResult.ToList(), TypeArgumentStyles.Positional, errorList, Operator, out int SelectedIndex))
                        {
                            return(false);
                        }

                        IQueryOverloadType SelectedOverloadType = AsFunctionType.OverloadList[SelectedIndex];
                        resolvedResult   = new ResultType(SelectedOverloadType.ResultTypeList);
                        selectedFeature  = AsFunctionFeature;
                        selectedOverload = AsFunctionFeature.OverloadList[SelectedIndex];

                        IArgument         FirstArgument = new PositionalArgument(RightExpression);
                        IList <IArgument> ArgumentList  = new List <IArgument>()
                        {
                            FirstArgument
                        };

                        List <IExpressionType> MergedArgumentList = new List <IExpressionType>();
                        bool IsArgumentValid = Argument.Validate(ArgumentList, MergedArgumentList, out TypeArgumentStyles TypeArgumentStyle, errorList);
                        Debug.Assert(IsArgumentValid);

                        featureCall       = new FeatureCall(SelectedOverloadType.ParameterTable, SelectedOverloadType.ResultTable, ArgumentList, MergedArgumentList, TypeArgumentStyle);
                        resolvedException = new ResultException(SelectedOverloadType.ExceptionIdentifierList);

                        constantSourceList.Add(LeftExpression);
                        constantSourceList.Add(RightExpression);
                    }
                    else
                    {
                        errorList.AddError(new ErrorInvalidOperator(Operator, OperatorName));
                        return(false);
                    }
                }
                else
                {
                    errorList.AddError(new ErrorInvalidExpression(LeftExpression));
                    return(false);
                }
            }
        public sealed override void Initialize(AnalysisContext context)
        {
            context.RegisterOperationAction(
                (operationContext) =>
            {
                ILoopStatement loop = (ILoopStatement)operationContext.Operation;
                if (loop.LoopKind == LoopKind.For)
                {
                    IForLoopStatement forLoop = (IForLoopStatement)loop;
                    IExpression forCondition  = forLoop.Condition;

                    if (forCondition.Kind == OperationKind.BinaryOperatorExpression)
                    {
                        IBinaryOperatorExpression condition = (IBinaryOperatorExpression)forCondition;
                        IExpression conditionLeft           = condition.Left;
                        IExpression conditionRight          = condition.Right;

                        if (conditionRight.ConstantValue != null &&
                            conditionRight.ResultType.SpecialType == SpecialType.System_Int32 &&
                            conditionLeft.Kind == OperationKind.LocalReferenceExpression)
                        {
                            // Test is known to be a comparison of a local against a constant.

                            int testValue             = (int)conditionRight.ConstantValue;
                            ILocalSymbol testVariable = ((ILocalReferenceExpression)conditionLeft).Local;

                            if (forLoop.Before.Length == 1)
                            {
                                IStatement setup = forLoop.Before[0];
                                if (setup.Kind == OperationKind.ExpressionStatement && ((IExpressionStatement)setup).Expression.Kind == OperationKind.AssignmentExpression)
                                {
                                    IAssignmentExpression setupAssignment = (IAssignmentExpression)((IExpressionStatement)setup).Expression;
                                    if (setupAssignment.Target.Kind == OperationKind.LocalReferenceExpression &&
                                        ((ILocalReferenceExpression)setupAssignment.Target).Local == testVariable &&
                                        setupAssignment.Value.ConstantValue != null &&
                                        setupAssignment.Value.ResultType.SpecialType == SpecialType.System_Int32)
                                    {
                                        // Setup is known to be an assignment of a constant to the local used in the test.

                                        int initialValue = (int)setupAssignment.Value.ConstantValue;

                                        if (forLoop.AtLoopBottom.Length == 1)
                                        {
                                            IStatement advance = forLoop.AtLoopBottom[0];
                                            if (advance.Kind == OperationKind.ExpressionStatement)
                                            {
                                                IExpression advanceExpression            = ((IExpressionStatement)advance).Expression;
                                                IExpression advanceIncrement             = null;
                                                BinaryOperationKind advanceOperationCode = BinaryOperationKind.None;

                                                if (advanceExpression.Kind == OperationKind.AssignmentExpression)
                                                {
                                                    IAssignmentExpression advanceAssignment = (IAssignmentExpression)advanceExpression;

                                                    if (advanceAssignment.Target.Kind == OperationKind.LocalReferenceExpression &&
                                                        ((ILocalReferenceExpression)advanceAssignment.Target).Local == testVariable &&
                                                        advanceAssignment.Value.Kind == OperationKind.BinaryOperatorExpression &&
                                                        advanceAssignment.Value.ResultType.SpecialType == SpecialType.System_Int32)
                                                    {
                                                        // Advance is known to be an assignment of a binary operation to the local used in the test.

                                                        IBinaryOperatorExpression advanceOperation = (IBinaryOperatorExpression)advanceAssignment.Value;
                                                        if (!advanceOperation.UsesOperatorMethod &&
                                                            advanceOperation.Left.Kind == OperationKind.LocalReferenceExpression &&
                                                            ((ILocalReferenceExpression)advanceOperation.Left).Local == testVariable &&
                                                            advanceOperation.Right.ConstantValue != null &&
                                                            advanceOperation.Right.ResultType.SpecialType == SpecialType.System_Int32)
                                                        {
                                                            // Advance binary operation is known to involve a reference to the local used in the test and a constant.
                                                            advanceIncrement     = advanceOperation.Right;
                                                            advanceOperationCode = advanceOperation.BinaryKind;
                                                        }
                                                    }
                                                }
                                                else if (advanceExpression.Kind == OperationKind.CompoundAssignmentExpression || advanceExpression.Kind == OperationKind.IncrementExpression)
                                                {
                                                    ICompoundAssignmentExpression advanceAssignment = (ICompoundAssignmentExpression)advanceExpression;

                                                    if (advanceAssignment.Target.Kind == OperationKind.LocalReferenceExpression &&
                                                        ((ILocalReferenceExpression)advanceAssignment.Target).Local == testVariable &&
                                                        advanceAssignment.Value.ConstantValue != null &&
                                                        advanceAssignment.Value.ResultType.SpecialType == SpecialType.System_Int32)
                                                    {
                                                        // Advance binary operation is known to involve a reference to the local used in the test and a constant.
                                                        advanceIncrement     = advanceAssignment.Value;
                                                        advanceOperationCode = advanceAssignment.BinaryKind;
                                                    }
                                                }

                                                if (advanceIncrement != null)
                                                {
                                                    int incrementValue = (int)advanceIncrement.ConstantValue;
                                                    if (advanceOperationCode == BinaryOperationKind.IntegerSubtract)
                                                    {
                                                        advanceOperationCode = BinaryOperationKind.IntegerAdd;
                                                        incrementValue       = -incrementValue;
                                                    }

                                                    if (advanceOperationCode == BinaryOperationKind.IntegerAdd &&
                                                        incrementValue != 0 &&
                                                        (condition.BinaryKind == BinaryOperationKind.IntegerLessThan ||
                                                         condition.BinaryKind == BinaryOperationKind.IntegerLessThanOrEqual ||
                                                         condition.BinaryKind == BinaryOperationKind.IntegerNotEquals ||
                                                         condition.BinaryKind == BinaryOperationKind.IntegerGreaterThan ||
                                                         condition.BinaryKind == BinaryOperationKind.IntegerGreaterThanOrEqual))
                                                    {
                                                        int iterationCount = (testValue - initialValue) / incrementValue;
                                                        if (iterationCount >= 1000000)
                                                        {
                                                            Report(operationContext, forLoop.Syntax, BigForDescriptor);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
                OperationKind.LoopStatement);
        }
 /// <inheritdoc />
 public override Expression VisitBinaryOperatorExpression(IBinaryOperatorExpression operation, LocalBinder argument)
 {
     return(base.VisitBinaryOperatorExpression(operation, argument));
 }
Exemple #28
0
 public override IOperation VisitBinaryOperatorExpression(IBinaryOperatorExpression operation, object argument)
 {
     return(new BinaryOperatorExpression(operation.OperatorKind, Visit(operation.LeftOperand), Visit(operation.RightOperand), operation.IsLifted, operation.IsChecked, operation.IsCompareText, operation.UsesOperatorMethod, operation.OperatorMethod, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit));
 }