コード例 #1
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    var outcome = query.IsLessThan(this.PC, this.left, this.right);

                    switch (outcome)
                    {
                    case ProofOutcome.Top:
                    {
                        // Let us see if there is a possible off-by-one
                        var offByOne = query.IsTrue(this.PC, BoxedExpression.Binary(BinaryOperator.Cle, this.left, this.right));
                        if (offByOne == ProofOutcome.True)
                        {
                            this.AdditionalInformationOnTheWarning.Add(new WarningContext(WarningContext.ContextType.OffByOne));
                        }

                        return(outcome);
                    }

                    case ProofOutcome.Bottom:
                    case ProofOutcome.False:
                    case ProofOutcome.True:
                    {
                        return(outcome);
                    }

                    default:
                    {
                        Contract.Assert(false);
                        return(outcome); // unreached
                    }
                    }
                }
コード例 #2
0
        protected override ProofOutcome ValidateInternal(IFactQuery <Exp, Var> query, ContractInferenceManager inferenceManager, IOutputResults output)
        {
            Contract.Requires(query != null);
            Contract.Requires(inferenceManager != null);

            throw new NotImplementedException();
        }
コード例 #3
0
                /// <summary>
                /// If we cannot validate the precision of the operands, we try to suggest an explicit cast
                /// </summary>
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    var outcome = query.HaveSameFloatType(PC, this.left, this.right);

                    switch (outcome)
                    {
                    case ProofOutcome.Top:
                    {
                        ConcreteFloat leftType, rightType;

                        if (query.TryGetFloatType(this.PC, this.left, out leftType) && query.TryGetFloatType(this.PC, this.right, out rightType))
                        {
                            APC conditionPC;
                            if (!this.MethodDriver.AdditionalSyntacticInformation.VariableDefinitions.TryGetValue(this.var, out conditionPC))
                            {
                                conditionPC = this.PC;
                            }

                            if (inferenceManager.CodeFixesManager.TrySuggestFloatingPointComparisonFix(this, conditionPC, this.left, this.right, leftType, rightType))
                            {
                                // do something? Returning true seems a bad idea
                            }
                        }

                        return(outcome);
                    }

                    default:
                    {
                        return(outcome);
                    }
                    }
                }
コード例 #4
0
            public static void ValidateAssertions(IFactQuery <BoxedExpression, TVariable> facts, IMethodDriver <TExpression, TVariable> driver, List <string> proofResults)
            {
                APC entryAfterRequires = driver.ContextProvider.MethodContext.CFG.EntryAfterRequires;

                if (facts.IsUnreachable(entryAfterRequires))
                {
                    proofResults.Add("Method precondition is unsatisfiable");
                    return;
                }

                object assertStats;

                foreach (AssertionObligation obl in GetAssertions(driver, out assertStats))
                {
                    FlatDomain <bool> outcome = facts.IsTrue(obl.Apc, BoxedExpression.For(driver.ContextProvider.ExpressionContext.Refine(obl.Apc, obl.Condition), driver.ExpressionDecoder));

                    string pc = obl.Apc.ToString();

                    if (outcome.IsNormal())
                    {
                        proofResults.Add(string.Format("Assertion at point {0} is {1}", pc, outcome.IsTrue() ? "true" : "false"));
                    }
                    else if (outcome.IsTop)
                    {
                        proofResults.Add("Assertion at point " + pc + " is unproven");
                    }
                    else
                    {
                        proofResults.Add("Assertion at point " + pc + " is unreachable");
                    }
                }
            }
コード例 #5
0
                protected override sealed ProofOutcome ValidateInternal(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    if (this.MethodDriver.Options.TraceChecks)
                    {
                        output.WriteLine("Validating proof obligation: {0}", this.Condition != null ? this.Condition.ToString() : "<null?>");
                    }

                    var result = ValidateInternalSpecific(query, inferenceManager, output);

                    if (result != ProofOutcome.Top)
                    {
                        return(result);
                    }

                    var condition = this.Condition;

                    if (condition != null)
                    {
                        WeakestPreconditionProver.AdditionalInfo why;
                        if (TryDischargeProofObligationWithWeakestPreconditions(condition, query, inferenceManager, output, out why))
                        {
                            return(ProofOutcome.True);
                        }
                        else
                        {
                            this.AdditionalInformationOnTheWarning.AddRange(WarningContextFetcher.InferContext(this.PC, condition, this.Context, this.DecoderForMetaData.IsBoolean));
                            this.AdditionalInformationOnTheWarning.AddRange(why.GetWarningContexts());
                        }
                    }
                    return(ProofOutcome.Top);
                }
コード例 #6
0
ファイル: AnimalFacts.cs プロジェクト: ashab015/AnimalFacts
        public async Task <IReadOnlyList <Fact> > GetFacts(IFactQuery query)
        {
            try
            {
                var qeuryUrl        = query.ToQueryUrl();
                var responseMessage = await _httpClient.GetAsync($"{ANIMAL_FACTS_URL}{qeuryUrl}");

                var content = await responseMessage.Content.ReadAsStringAsync();

                if (query.Amount == 1)
                {
                    var fact = JsonConvert.DeserializeObject <Fact>(content);
                    return(new List <Fact>()
                    {
                        fact
                    });
                }
                else
                {
                    return(JsonConvert.DeserializeObject <List <Fact> >(content));
                }
            }
            catch (Exception ex)
            {
                return(default(List <Fact>));
            }
        }
コード例 #7
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    // First, we check if arg != MinValue

                    object value;

                    if (!this.DecoderForMetaData.TryGetMinValueForType(this.typeOfArg, out value))
                    {
                        return(ProofOutcome.Top);
                    }

                    var condition = this.Condition;

                    if (condition != null) // this.Condition may return null
                    {
                        var result = query.IsTrue(this.PC, condition);

                        if (result != ProofOutcome.Top)
                        {
                            return(result);
                        }
                    }
                    // We check a sufficient condition: if arg is >= 0, then it is not the negation of a negative "extreme"
                    var greaterThanZero = query.IsGreaterEqualToZero(this.PC, this.arg);

                    return((greaterThanZero == ProofOutcome.True || greaterThanZero == ProofOutcome.Bottom)
            ? greaterThanZero : ProofOutcome.Top);
                }
コード例 #8
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    // Check if expForIndex >= 0
                    return(query.IsGreaterEqualToZero(this.PC, index));

#if false
                    // Try to use weakest preconditions
                    if (result == ProofOutcome.Top)
                    {
                        if (CanAssumeLowerBoundPrecondition(output, this.index))
                        {
                            result = ProofOutcome.True;
                        }
                        else
                        {
                            // if we have lb <= i, then we can suggest 0 <= lb
                            //
                            foreach (Variable lb in query.LowerBounds(this.PC, index, false))
                            {
                                BoxedExpression lbbox = BoxedExpression.Var(lb);
                                if (CanAssumeLowerBoundPrecondition(output, lbbox))
                                {
                                    result = ProofOutcome.True;
                                }
                            }
                        }
                    }

                    return(result);
#endif
                }
コード例 #9
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    object minValue;

                    if (!this.DecoderForMetaData.TryGetMinValueForType(this.TypeOp1, out minValue))
                    {
                        return(ProofOutcome.Top);
                    }

                    // first, we check that Op1 != MinValue
                    var condition1 = BoxedExpression.Binary(BinaryOperator.Cne_Un, this.Op1, BoxedExpression.Const(minValue, this.TypeOp1, this.DecoderForMetaData));
                    var resultOp1  = query.IsTrue(this.PC, condition1);

                    // second, we check Op2 != -1
                    var condition2 = BoxedExpression.Binary(BinaryOperator.Cne_Un, this.Op2, BoxedExpression.Const(-1, this.DecoderForMetaData.System_Int32, this.DecoderForMetaData));
                    var resultOp2  = query.IsTrue(this.PC, condition2);

                    // One of the two conditions is true, so it is ok!
                    if (resultOp1 == ProofOutcome.True || resultOp2 == ProofOutcome.True)
                    {
                        return(ProofOutcome.True);
                    }

                    // Both conditions are false, so division is definitely an overflow
                    if (resultOp1 == ProofOutcome.False && resultOp2 == ProofOutcome.False)
                    {
                        return(ProofOutcome.False);
                    }

                    return(ProofOutcome.Top);
                }
コード例 #10
0
 public void Add(IFactQuery <BoxedExpression, Variable> item)
 {
     if (item == null)
     {
         return;
     }
     this.elements.Add(item);
 }
コード例 #11
0
 public SearchWitnesses
 (
     IFactQuery <BoxedExpression, Variable> facts,
     IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions> mdriver,
     TimeOutChecker timeout)
     : base(mdriver.CFG.NormalExit, facts, mdriver, timeout)
 {
     this.Found  = false;
     this.Result = Witness.None;
 }
コード例 #12
0
        public ParametersSuggestNonOverflowingExpression(APC pc, Func <APC, APC> pcWithSourceContext, BoxedExpression exp, IFactQuery <BoxedExpression, Variable> factQuery, Func <APC, BoxedExpression, bool, BoxedExpression> Simplificator, Func <Variable, IntervalStruct> TypeRange)
        {
            Contract.Requires(pcWithSourceContext != null);

            this.pc = pc;
            this.pcWithSourceContext = pcWithSourceContext(pc);
            this.exp           = exp;
            this.factQuery     = factQuery;
            this.Simplificator = Simplificator;
            this.TypeRange     = TypeRange;
        }
コード例 #13
0
 Analyze <Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, Expression, Variable>(
     string fullMethodName,
     IMethodDriver <APC, Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, Expression, Variable, ILogOptions> mdriver,
     IFactQuery <BoxedExpression, Variable> factQuery
     )
     where Variable : IEquatable <Variable>
     where Expression : IEquatable <Expression>
     where Type : IEquatable <Type>
 {
     return(Analyze(fullMethodName, mdriver));
 }
コード例 #14
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    // If it is a variable or a constant, then there is nothing to do, and we return true.

                    if (this.exp.IsConstant || this.exp.IsVariable)
                    {
                        return(ProofOutcome.True);
                    }

                    return(base.ValidateInternalSpecific(query, inferenceManager, output));
                }
コード例 #15
0
                    protected override ProofOutcome ValidateInternal(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                    {
                        ProofOutcome outcome;

                        if ((outcome = query.IsVariableDefinedForType(this.PC, this.value, this.type)) != ProofOutcome.Top)
                        {
                            return(outcome);
                        }

                        return(ProofOutcome.Top);
                    }
コード例 #16
0
                    protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                    {
                        Contract.Assume(query != null, "should be a precondition");

                        if (this.uncheckable)
                        {
                            return(ProofOutcome.Top);
                        }

                        return(query.IsTrue(this.PC, condition));
                    }
コード例 #17
0
 internal PartitionAnalysis(
     string methodName,
     IMethodDriver <APC, Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable, ILogOptions> mdriver,
     List <Analyzers.Containers.ContainerOptions> optionsList,
     IFactQuery <BoxedExpression, Variable> factQuery)
     : base(methodName, mdriver, optionsList[0])
 {
     //this.mdriver = mdriver;
     //this.optionsList = optionsList;
     this.factQuery   = factQuery;
     this.obligations = new PartitionsObligations(mdriver, optionsList[0]);
 }
コード例 #18
0
            public PreconditionsInferenceBackwardSymbolic(
                IFactQuery <BoxedExpression, Variable> facts,
                IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions> mdriver
                )
            {
                Contract.Requires(facts != null);
                Contract.Requires(mdriver != null);

                this.Facts   = facts;
                this.MDriver = mdriver;
                this.timeout = new TimeOutChecker(TIMEOUT, false); // we do not start the timeout, because we want to do it only for effective computations
            }
コード例 #19
0
                protected override ProofOutcome ValidateInternalSpecific(IFactQuery <BoxedExpression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
                {
                    // We check the condition
                    var condition = this.Condition;

                    if (condition == null)
                    {
                        return(ProofOutcome.Top);
                    }

                    return(query.IsTrue(this.PC, condition));
                }
コード例 #20
0
        public CodeFixesForOverflowingExpression(APC pc, IFactQuery <BoxedExpression, Var> facts, LazyEval <BoxedExpression> ZeroExp)
        {
            Contract.Requires(facts != null);
            Contract.Requires(ZeroExp != null);

            this.PC             = pc;
            this.Facts          = facts;
            this.OverflowOracle = new FactQueryForOverflow <Var>(facts);
            this.ExpressionTags = new Dictionary <BoxedExpression, State>();
            this.ZeroExp        = ZeroExp;
            this.PartialResult  = null;
        }
コード例 #21
0
 virtual public IMethodResult <Variable> Analyze <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable>(
     string fullMethodName,
     IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, ILogOptions> driver,
     Predicate <APC> cachePCs,
     IFactQuery <BoxedExpression, Variable> factQuery
     )
     where Type : IEquatable <Type>
     where Expression : IEquatable <Expression>
     where Variable : IEquatable <Variable>
 {
     return(Analyze(fullMethodName, driver, cachePCs));
 }
コード例 #22
0
        public ParametersSuggestOffByOneFix(ProofObligation obl, APC pc, Func <APC, APC> pcWithSourceContext, bool isArrayAccess, BoxedExpression exp, Func <Variable, FList <PathElement> > AccessPath, Func <BoxedExpression, bool> IsArrayLength, IFactQuery <BoxedExpression, Variable> factQuery)
        {
            Contract.Requires(pcWithSourceContext != null);

            this.obl = obl;
            this.pc  = pc;
            this.pcWithSourceContext = pcWithSourceContext(pc);
            this.isArrayAccess       = isArrayAccess;
            this.exp           = exp;
            this.AccessPath    = AccessPath;
            this.IsArrayLength = IsArrayLength;
            this.factQuery     = factQuery;
        }
コード例 #23
0
                public BackwardsPropagation(
                    APC pcCondition,
                    IFactQuery <BoxedExpression, Variable> facts,
                    IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions> mdriver,
                    TimeOutChecker timeout)
                {
                    Contract.Requires(mdriver != null);

                    this.pcCondition = pcCondition;
                    this.facts       = facts;
                    this.Mdriver     = mdriver;
                    this.CFG         = this.Mdriver.StackLayer.Decoder.Context.MethodContext.CFG;
                    this.timeout     = timeout;
                    this.joinPoints  = new Dictionary <APC, Preconditions>();
                }
コード例 #24
0
        RunPartitionAnalysis <Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable>
        (
            string methodName,
            IMethodDriver <APC, Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable, ILogOptions> driver,
            List <Analyzers.Containers.ContainerOptions> options,
            IFactQuery <BoxedExpression, Variable> factQuery)
            where Variable : IEquatable <Variable>
            where ExternalExpression : IEquatable <ExternalExpression>
            where Type : IEquatable <Type>
        {
            //var analysis =
            // new TypeBindings<Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable>.PartitionAnalysis(methodName, driver, options);

            return(TypeBindings <Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable> .HelperForPartitionAnalysis(methodName, driver, options, factQuery));
        }
コード例 #25
0
        public GenericNecessaryConditionsGenerator(
            APC pcCondition,
            IFactQuery <BoxedExpression, Variable> facts,
            IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions> mdriver,
            TimeOutChecker timeout)
        {
            Contract.Requires(mdriver != null);

            this.pcCondition      = pcCondition;
            this.facts            = facts;
            this.Mdriver          = mdriver;
            this.CFG              = this.Mdriver.StackLayer.Decoder.Context.MethodContext.CFG;
            this.underVisit       = new Set <APC>();
            this.timeout          = timeout;
            this.ExpressionReader = new ExpressionReader <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable>();
            this.SatisfyProcedure = new SimpleSatisfyProcedure <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly>(mdriver.MetaDataDecoder);
            this.LoopHit          = false;
            this.mutator          = new ReplaceSymbolicValueForAccessPath <Local, Parameter, Method, Field, Property, Event, Type, Variable, Expression, Attribute, Assembly>(mdriver.Context, mdriver.MetaDataDecoder);
        }
コード例 #26
0
            /// <summary>
            /// method calling the analysis of containers, wich is preceded by a partition analysis of containers
            /// </summary>
            public override IMethodResult <Variable> Analyze <Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, Expression, Variable>(
                string fullMethodName,
                IMethodDriver <APC, Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, Expression, Variable, ILogOptions> mdriver,
                IFactQuery <BoxedExpression, Variable> factQuery)
            // where Variable : IEquatable<Variable>
            // where Expression : IEquatable<Expression>
            // where Type : IEquatable<Type>
            {
                //IMethodResult<Variable> partitions = AnalysisWrapper.RunPartitionAnalysis(fullMethodName, mdriver, this.options); //t-maper@54: do I need a different set of options for the partition analyis or I mixed it with the options of Container Analysis?

                //return AnalysisWrapper.RunContainerAnalysis(fullMethodName, mdriver, partitions, this.options); //t-maper@54: this.options[0] ?

                var partitionsResult = AnalysisWrapper.RunPartitionAnalysis(fullMethodName, mdriver, this.options, factQuery);

                var containersResult = AnalysisWrapper.RunContainerAnalysis(fullMethodName, mdriver, partitionsResult, this.options);

                containersResult.MethodAnalysis = this; // Mic: keep track of the analysis that gave the result
                return(containersResult);
                //return partitionsResult;
            }
コード例 #27
0
            HelperForPartitionAnalysis(string methodName,
                                       IMethodDriver <APC, Local, Parameter, Method, Field, Property, Type, Attribute, Assembly, ExternalExpression, Variable, ILogOptions> driver,
                                       List <Analyzers.Containers.ContainerOptions> optionsList,
                                       IFactQuery <BoxedExpression, Variable> factQuery)
            {
                PartitionAnalysis analysis;

                analysis = new PartitionAnalysis(methodName, driver, optionsList, factQuery);

                // *** The next lines must be strictly sequential ***
                var closure = driver.CreateForward <SimplePartitionAbstractDomain <BoxedVariable <Variable>, BoxedExpression> >(analysis);

                // At this point, CreateForward has called the Visitor, so the context has been created, so that now we can call initValue

                SimplePartitionAbstractDomain <BoxedVariable <Variable>, BoxedExpression> .Trace = optionsList[0].TracePartitionAnalysis;

                var initValue = analysis.InitialValue;

                closure(initValue); // Do the analysis

                return(analysis);
            }
コード例 #28
0
        public ProofOutcome Validate(IFactQuery <Expression, Variable> query, ContractInferenceManager inferenceManager, IOutputResults output)
        {
            ProofOutcome outcome;

            if (query.IsUnreachable(this.PCForValidation))
            {
                outcome = ProofOutcome.Bottom;
            }
            else
            {
                outcome = ValidateInternal(query, inferenceManager, output);

                if (outcome == ProofOutcome.Top || outcome == ProofOutcome.False)
                {
                    if (this.Condition != null && this.TryInferPrecondition && !output.IsMasked(this.GetWitness(outcome)))
                    {
                        InferredConditions inferredPreConditions;

                        var inferencer = inferenceManager.PreCondition.Inference;
                        if (inferencer.TryInferConditions(this, inferenceManager.CodeFixesManager, out inferredPreConditions))
                        {
                            var context = inferredPreConditions.PushToContractManager(inferenceManager, inferencer.ShouldAddAssumeFalse, this, ref outcome, output.LogOptions);

                            this.HasASufficientAndNecessaryCondition = inferredPreConditions.HasASufficientCondition;
                            this.AdditionalInformationOnTheWarning.AddRange(context);
                        }
                        else if (inferencer.ShouldAddAssumeFalse)
                        {
                            inferenceManager.Assumptions.AddEntryAssumes(this, new BoxedExpression[] { BoxedExpression.ConstFalse });
                        }
                    }
                }
            }

            this.Outcome = outcome;

            return(outcome);
        }
コード例 #29
0
                public IEnumerable <BoxedExpression> InferredPreconditions(IFactQuery <BoxedExpression, Variable> facts)
                {
                    var result = new List <BoxedExpression>();

                    foreach (var pre in this.invariants)
                    {
                        switch (facts.IsTrue(this.Mdriver.CFG.EntryAfterRequires, pre))
                        {
                        case ProofOutcome.Bottom:
                        case ProofOutcome.False:
                            return(null);

                        case ProofOutcome.True:
                            continue;

                        case ProofOutcome.Top:
                            result.Add(pre);
                            break;
                        }
                    }

                    return(result.SyntacticReductionRemoval(removeChecksWithMinValue: true));
                }
コード例 #30
0
            public static void ValidateAssertions(IFactQuery <BoxedExpression, TVariable> facts, IMethodDriver <TExpression, TVariable> driver, List <string> proofResults)
            {
                APC entryAfterRequires = driver.ContextProvider.MethodContext.CFG.EntryAfterRequires;

                if (facts.IsUnreachable(entryAfterRequires))
                {
                    proofResults.Add("Method precondition is unsatisfiable");
                    return;
                }

                object assertStats;

                foreach (AssertionObligation obl in GetAssertions(driver, out assertStats))
                {
                    ProofOutcome outcome = facts.IsTrue(obl.Apc, BoxedExpression.For(driver.ContextProvider.ExpressionContext.Refine(obl.Apc, obl.Condition), driver.ExpressionDecoder));

                    string pc = obl.Apc.ToString();
                    switch (outcome)
                    {
                    case ProofOutcome.Top:
                        proofResults.Add("Assertion at point " + pc + " is unproven");
                        break;

                    case ProofOutcome.True:
                        proofResults.Add("Assertion at point " + pc + " is true");
                        break;

                    case ProofOutcome.False:
                        proofResults.Add("Assertion at point " + pc + " is false");
                        break;

                    case ProofOutcome.Bottom:
                        proofResults.Add("Assertion at point " + pc + " is unreachable");
                        break;
                    }
                }
            }
コード例 #31
0
 public UnderflowVisitor(APC pc, IFactQuery<BoxedExpression, Variable> facts)
     : base(pc, facts)
 {
 }