Branch data Line data Source code
1 : : /******************************************************************************
2 : : * Top contributors (to current version):
3 : : * Abdalrhman Mohamed, Andrew Reynolds, Andres Noetzli
4 : : *
5 : : * This file is part of the cvc5 project.
6 : : *
7 : : * Copyright (c) 2009-2024 by the authors listed in the file AUTHORS
8 : : * in the top-level source directory and their institutional affiliations.
9 : : * All rights reserved. See the file COPYING in the top-level source
10 : : * directory for licensing information.
11 : : * ****************************************************************************
12 : : *
13 : : * Base of the pretty-printer interface.
14 : : */
15 : : #include "printer/printer.h"
16 : :
17 : : #include <sstream>
18 : : #include <string>
19 : :
20 : : #include "expr/node.h"
21 : : #include "options/base_options.h"
22 : : #include "options/language.h"
23 : : #include "options/printer_options.h"
24 : : #include "printer/ast/ast_printer.h"
25 : : #include "printer/let_binding.h"
26 : : #include "printer/smt2/smt2_printer.h"
27 : : #include "proof/unsat_core.h"
28 : : #include "smt/model.h"
29 : : #include "theory/quantifiers/instantiation_list.h"
30 : :
31 : : using namespace std;
32 : :
33 : : namespace cvc5::internal {
34 : :
35 : : unique_ptr<Printer>
36 : : Printer::d_printers[static_cast<size_t>(Language::LANG_MAX)];
37 : :
38 : 18218 : unique_ptr<Printer> Printer::makePrinter(Language lang)
39 : : {
40 [ + + ][ + - ]: 18218 : switch(lang) {
41 : 17317 : case Language::LANG_SMTLIB_V2_6:
42 : 17317 : return unique_ptr<Printer>(new printer::smt2::Smt2Printer);
43 : :
44 : 900 : case Language::LANG_SYGUS_V2:
45 : : // sygus version 2.0 does not have discrepancies with smt2, hence we use
46 : : // a normal smt2 variant here.
47 : 900 : return unique_ptr<Printer>(new printer::smt2::Smt2Printer);
48 : :
49 : 1 : case Language::LANG_AST:
50 : 1 : return unique_ptr<Printer>(new printer::ast::AstPrinter());
51 : :
52 : 0 : default: Unhandled() << lang;
53 : : }
54 : : }
55 : :
56 : 0 : void Printer::toStream(std::ostream& out,
57 : : TNode n,
58 : : const LetBinding* lbind,
59 : : bool lbindTop) const
60 : : {
61 : : // no special implementation, just convert and print with default prefix
62 [ - - ]: 0 : if (lbind != nullptr)
63 : : {
64 : 0 : Node nc = lbind->convert(n, lbindTop);
65 : 0 : toStream(out, nc);
66 : : }
67 : : else
68 : : {
69 : 0 : toStream(out, n);
70 : : }
71 : 0 : }
72 : :
73 : 210 : void Printer::toStream(std::ostream& out, const smt::Model& m) const
74 : : {
75 : : // print the declared sorts
76 : 210 : const std::vector<TypeNode>& dsorts = m.getDeclaredSorts();
77 [ + + ]: 381 : for (const TypeNode& tn : dsorts)
78 : : {
79 : 171 : toStreamModelSort(out, tn, m.getDomainElements(tn));
80 : : }
81 : : // print the declared terms
82 : 210 : const std::vector<Node>& dterms = m.getDeclaredTerms();
83 [ + + ]: 599 : for (const Node& n : dterms)
84 : : {
85 : 389 : toStreamModelTerm(out, n, m.getValue(n));
86 : : }
87 : 210 : }
88 : :
89 : 0 : void Printer::toStream(std::ostream& out, const UnsatCore& core) const
90 : : {
91 [ - - ]: 0 : for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
92 : 0 : toStreamCmdAssert(out, *i);
93 : 0 : out << std::endl;
94 : : }
95 : 0 : }/* Printer::toStream(UnsatCore) */
96 : :
97 : 75 : void Printer::toStream(std::ostream& out, const InstantiationList& is) const
98 : : {
99 : 75 : out << "(instantiations " << is.d_quant << std::endl;
100 [ + + ]: 150 : for (const InstantiationVec& i : is.d_inst)
101 : : {
102 : 75 : out << " ";
103 [ - + ]: 75 : if (i.d_id != theory::InferenceId::UNKNOWN)
104 : : {
105 : 0 : out << "(! ";
106 : : }
107 : 75 : out << "( ";
108 [ + + ]: 150 : for (const Node& n : i.d_vec)
109 : : {
110 : 75 : out << n << " ";
111 : : }
112 : 75 : out << ")";
113 [ - + ]: 75 : if (i.d_id != theory::InferenceId::UNKNOWN)
114 : : {
115 : 0 : out << " :source " << i.d_id;
116 [ - - ]: 0 : if (!i.d_pfArg.isNull())
117 : : {
118 : 0 : out << " " << i.d_pfArg;
119 : : }
120 : 0 : out << ")";
121 : : }
122 : 75 : out << std::endl;
123 : : }
124 : 75 : out << ")" << std::endl;
125 : 75 : }
126 : :
127 : 6 : void Printer::toStream(std::ostream& out, const SkolemList& sks) const
128 : : {
129 : 6 : out << "(skolem " << sks.d_quant << std::endl;
130 : 6 : out << " ( ";
131 [ + + ]: 12 : for (const Node& n : sks.d_sks)
132 : : {
133 : 6 : out << n << " ";
134 : : }
135 : 6 : out << ")" << std::endl;
136 : 6 : out << ")" << std::endl;
137 : 6 : }
138 : :
139 : 14108500 : Printer* Printer::getPrinter(std::ostream& out)
140 : : {
141 : 14108500 : Language lang = options::ioutils::getOutputLanguage(out);
142 : 14108500 : return getPrinter(lang);
143 : : }
144 : :
145 : 14108500 : Printer* Printer::getPrinter(Language lang)
146 : : {
147 [ + + ]: 14108500 : if (lang == Language::LANG_AUTO)
148 : : {
149 : 10797 : lang = Language::LANG_SMTLIB_V2_6; // default
150 : : }
151 [ + + ]: 14108500 : if (d_printers[static_cast<size_t>(lang)] == nullptr)
152 : : {
153 : 18218 : d_printers[static_cast<size_t>(lang)] = makePrinter(lang);
154 : : }
155 : 14108500 : return d_printers[static_cast<size_t>(lang)].get();
156 : : }
157 : :
158 : 0 : void Printer::printUnknownCommandStatus(std::ostream& out,
159 : : const std::string& name) const
160 : : {
161 : 0 : out << "ERROR: don't know how to print " << name << " command status"
162 : 0 : << std::endl;
163 : 0 : }
164 : :
165 : 0 : void Printer::printUnknownCommand(std::ostream& out,
166 : : const std::string& name) const
167 : : {
168 : 0 : out << "ERROR: don't know how to print " << name << " command";
169 : 0 : }
170 : :
171 : 0 : void Printer::toStreamCmdSuccess(std::ostream& out) const
172 : : {
173 : 0 : printUnknownCommandStatus(out, "success");
174 : 0 : }
175 : :
176 : 0 : void Printer::toStreamCmdInterrupted(std::ostream& out) const
177 : : {
178 : 0 : printUnknownCommandStatus(out, "interrupted");
179 : 0 : }
180 : :
181 : 0 : void Printer::toStreamCmdUnsupported(std::ostream& out) const
182 : : {
183 : 0 : printUnknownCommandStatus(out, "unsupported");
184 : 0 : }
185 : :
186 : 0 : void Printer::toStreamCmdFailure(std::ostream& out,
187 : : const std::string& message) const
188 : : {
189 : 0 : printUnknownCommandStatus(out, "failure");
190 : 0 : }
191 : :
192 : 0 : void Printer::toStreamCmdRecoverableFailure(std::ostream& out,
193 : : const std::string& message) const
194 : : {
195 : 0 : printUnknownCommandStatus(out, "recoverable-failure");
196 : 0 : }
197 : :
198 : 0 : void Printer::toStreamCmdEmpty(std::ostream& out, const std::string& name) const
199 : : {
200 : 0 : printUnknownCommand(out, "empty");
201 : 0 : }
202 : :
203 : 0 : void Printer::toStreamCmdEcho(std::ostream& out,
204 : : const std::string& output) const
205 : : {
206 : 0 : printUnknownCommand(out, "echo");
207 : 0 : }
208 : :
209 : 0 : void Printer::toStreamCmdAssert(std::ostream& out, Node n) const
210 : : {
211 : 0 : printUnknownCommand(out, "assert");
212 : 0 : }
213 : :
214 : 0 : void Printer::toStreamCmdPush(std::ostream& out, uint32_t nscopes) const
215 : : {
216 : 0 : printUnknownCommand(out, "push");
217 : 0 : }
218 : :
219 : 0 : void Printer::toStreamCmdPop(std::ostream& out, uint32_t nscopes) const
220 : : {
221 : 0 : printUnknownCommand(out, "pop");
222 : 0 : }
223 : :
224 : 0 : void Printer::toStreamCmdDeclareFunction(std::ostream& out,
225 : : const std::string& id,
226 : : const std::vector<TypeNode>& argTypes,
227 : : TypeNode type) const
228 : : {
229 : 0 : printUnknownCommand(out, "declare-fun");
230 : 0 : }
231 : :
232 : 15356 : void Printer::toStreamCmdDeclareFunction(std::ostream& out, const Node& v) const
233 : : {
234 : : // Must print the variable on the output stream (instead of just getting the
235 : : // name of v), since this method may be called on variables that do not have
236 : : // assigned names.
237 : 30712 : std::stringstream ss;
238 : 15356 : toStream(ss, v);
239 : 30712 : TypeNode vt = v.getType();
240 : 15356 : std::vector<TypeNode> argTypes;
241 [ + + ]: 15356 : if (vt.isFunction())
242 : : {
243 : 3803 : argTypes = vt.getArgTypes();
244 : 3803 : vt = vt.getRangeType();
245 : : }
246 : 15356 : toStreamCmdDeclareFunction(out, ss.str(), argTypes, vt);
247 : 15356 : }
248 : :
249 : 0 : void Printer::toStreamCmdDeclarePool(std::ostream& out,
250 : : const std::string& id,
251 : : TypeNode type,
252 : : const std::vector<Node>& initValue) const
253 : : {
254 : 0 : printUnknownCommand(out, "declare-pool");
255 : 0 : }
256 : :
257 : 0 : void Printer::toStreamCmdDeclareOracleFun(std::ostream& out,
258 : : const std::string& id,
259 : : const std::vector<TypeNode>& argTypes,
260 : : TypeNode type,
261 : : const std::string& binName) const
262 : : {
263 : 0 : printUnknownCommand(out, "declare-oracle-fun");
264 : 0 : }
265 : :
266 : 0 : void Printer::toStreamCmdDeclareType(std::ostream& out,
267 : : const std::string& id,
268 : : size_t arity) const
269 : : {
270 : 0 : printUnknownCommand(out, "declare-sort");
271 : 0 : }
272 : :
273 : 1277 : void Printer::toStreamCmdDeclareType(std::ostream& out, TypeNode type) const
274 : : {
275 [ + + ][ - + ]: 1277 : Assert(type.isUninterpretedSort() || type.isUninterpretedSortConstructor());
[ - + ][ - - ]
276 : 1277 : size_t arity = type.isUninterpretedSortConstructor()
277 [ + + ]: 1277 : ? type.getUninterpretedSortConstructorArity()
278 : 1277 : : 0;
279 : 1277 : toStreamCmdDeclareType(out, type.getName(), arity);
280 : 1277 : }
281 : :
282 : 0 : void Printer::toStreamCmdDefineType(std::ostream& out,
283 : : const std::string& id,
284 : : const std::vector<TypeNode>& params,
285 : : TypeNode t) const
286 : : {
287 : 0 : printUnknownCommand(out, "define-sort");
288 : 0 : }
289 : :
290 : 0 : void Printer::toStreamCmdDefineFunction(std::ostream& out,
291 : : const std::string& id,
292 : : const std::vector<Node>& formals,
293 : : TypeNode range,
294 : : Node formula) const
295 : : {
296 : 0 : printUnknownCommand(out, "define-fun");
297 : 0 : }
298 : :
299 : 405 : void Printer::toStreamCmdDefineFunction(std::ostream& out,
300 : : Node v,
301 : : Node lambda) const
302 : : {
303 : 810 : std::stringstream vs;
304 : 405 : vs << v;
305 : 810 : std::vector<Node> formals;
306 : 810 : Node body = lambda;
307 : 405 : TypeNode rangeType = v.getType();
308 [ + + ]: 405 : if (body.getKind() == Kind::LAMBDA)
309 : : {
310 : 2 : formals.insert(formals.end(), lambda[0].begin(), lambda[0].end());
311 : 2 : body = lambda[1];
312 [ - + ][ - + ]: 2 : Assert(rangeType.isFunction());
[ - - ]
313 : 2 : rangeType = rangeType.getRangeType();
314 : : }
315 : 405 : toStreamCmdDefineFunction(out, vs.str(), formals, rangeType, body);
316 : 405 : }
317 : :
318 : 0 : void Printer::toStreamCmdDefineFunctionRec(
319 : : std::ostream& out,
320 : : const std::vector<Node>& funcs,
321 : : const std::vector<std::vector<Node>>& formals,
322 : : const std::vector<Node>& formulas) const
323 : : {
324 : 0 : printUnknownCommand(out, "define-fun-rec");
325 : 0 : }
326 : :
327 : 0 : void Printer::toStreamCmdDefineFunctionRec(
328 : : std::ostream& out,
329 : : const std::vector<Node>& funcs,
330 : : const std::vector<Node>& lambdas) const
331 : : {
332 : 0 : std::vector<std::vector<Node>> formals;
333 : 0 : std::vector<Node> formulas;
334 [ - - ]: 0 : for (const Node& l : lambdas)
335 : : {
336 : 0 : std::vector<Node> formalsVec;
337 : 0 : Node formula;
338 [ - - ]: 0 : if (l.getKind() == Kind::LAMBDA)
339 : : {
340 : 0 : formalsVec.insert(formalsVec.end(), l[0].begin(), l[0].end());
341 : 0 : formula = l[1];
342 : : }
343 : : else
344 : : {
345 : 0 : formula = l;
346 : : }
347 : 0 : formals.emplace_back(formalsVec);
348 : 0 : formulas.emplace_back(formula);
349 : : }
350 : 0 : toStreamCmdDefineFunctionRec(out, funcs, formals, formulas);
351 : 0 : }
352 : :
353 : 0 : void Printer::toStreamCmdSetUserAttribute(std::ostream& out,
354 : : const std::string& attr,
355 : : Node n) const
356 : : {
357 : 0 : printUnknownCommand(out, "set-user-attribute");
358 : 0 : }
359 : :
360 : 0 : void Printer::toStreamCmdCheckSat(std::ostream& out) const
361 : : {
362 : 0 : printUnknownCommand(out, "check-sat");
363 : 0 : }
364 : :
365 : 0 : void Printer::toStreamCmdCheckSatAssuming(std::ostream& out,
366 : : const std::vector<Node>& nodes) const
367 : : {
368 : 0 : printUnknownCommand(out, "check-sat-assuming");
369 : 0 : }
370 : :
371 : 0 : void Printer::toStreamCmdQuery(std::ostream& out, Node n) const
372 : : {
373 : 0 : printUnknownCommand(out, "query");
374 : 0 : }
375 : :
376 : 0 : void Printer::toStreamCmdDeclareVar(std::ostream& out,
377 : : const std::string& id,
378 : : TypeNode type) const
379 : : {
380 : 0 : printUnknownCommand(out, "declare-var");
381 : 0 : }
382 : :
383 : 0 : void Printer::toStreamCmdSynthFun(std::ostream& out,
384 : : const std::string& id,
385 : : const std::vector<Node>& vars,
386 : : TypeNode rangeType,
387 : : TypeNode sygusType) const
388 : : {
389 : 0 : printUnknownCommand(out, "synth-fun");
390 : 0 : }
391 : :
392 : 0 : void Printer::toStreamCmdConstraint(std::ostream& out, Node n) const
393 : : {
394 : 0 : printUnknownCommand(out, "constraint");
395 : 0 : }
396 : :
397 : 0 : void Printer::toStreamCmdAssume(std::ostream& out, Node n) const
398 : : {
399 : 0 : printUnknownCommand(out, "assume");
400 : 0 : }
401 : :
402 : 0 : void Printer::toStreamCmdInvConstraint(
403 : : std::ostream& out, Node inv, Node pre, Node trans, Node post) const
404 : : {
405 : 0 : printUnknownCommand(out, "inv-constraint");
406 : 0 : }
407 : :
408 : 0 : void Printer::toStreamCmdCheckSynth(std::ostream& out) const
409 : : {
410 : 0 : printUnknownCommand(out, "check-synth");
411 : 0 : }
412 : 0 : void Printer::toStreamCmdCheckSynthNext(std::ostream& out) const
413 : : {
414 : 0 : printUnknownCommand(out, "check-synth-next");
415 : 0 : }
416 : :
417 : 0 : void Printer::toStreamCmdFindSynth(std::ostream& out,
418 : : modes::FindSynthTarget fst,
419 : : TypeNode sygusType) const
420 : : {
421 : 0 : printUnknownCommand(out, "find-synth");
422 : 0 : }
423 : :
424 : 0 : void Printer::toStreamCmdFindSynthNext(std::ostream& out) const
425 : : {
426 : 0 : printUnknownCommand(out, "find-synth-next");
427 : 0 : }
428 : :
429 : 0 : void Printer::toStreamCmdSimplify(std::ostream& out, Node n) const
430 : : {
431 : 0 : printUnknownCommand(out, "simplify");
432 : 0 : }
433 : :
434 : 0 : void Printer::toStreamCmdGetValue(std::ostream& out,
435 : : const std::vector<Node>& nodes) const
436 : : {
437 : 0 : printUnknownCommand(out, "get-value");
438 : 0 : }
439 : :
440 : 0 : void Printer::toStreamCmdGetAssignment(std::ostream& out) const
441 : : {
442 : 0 : printUnknownCommand(out, "get-assignment");
443 : 0 : }
444 : :
445 : 0 : void Printer::toStreamCmdGetModel(std::ostream& out) const
446 : : {
447 : 0 : printUnknownCommand(out, "ge-model");
448 : 0 : }
449 : :
450 : 0 : void Printer::toStreamCmdBlockModel(std::ostream& out,
451 : : modes::BlockModelsMode mode) const
452 : : {
453 : 0 : printUnknownCommand(out, "block-model");
454 : 0 : }
455 : :
456 : 0 : void Printer::toStreamCmdBlockModelValues(std::ostream& out,
457 : : const std::vector<Node>& nodes) const
458 : : {
459 : 0 : printUnknownCommand(out, "block-model-values");
460 : 0 : }
461 : :
462 : 0 : void Printer::toStreamCmdGetProof(std::ostream& out,
463 : : modes::ProofComponent c) const
464 : : {
465 : 0 : printUnknownCommand(out, "get-proof");
466 : 0 : }
467 : :
468 : 0 : void Printer::toStreamCmdGetInstantiations(std::ostream& out) const
469 : : {
470 : 0 : printUnknownCommand(out, "get-instantiations");
471 : 0 : }
472 : :
473 : 0 : void Printer::toStreamCmdGetInterpol(std::ostream& out,
474 : : const std::string& name,
475 : : Node conj,
476 : : TypeNode sygusType) const
477 : : {
478 : 0 : printUnknownCommand(out, "get-interpolant");
479 : 0 : }
480 : :
481 : 0 : void Printer::toStreamCmdGetInterpolNext(std::ostream& out) const
482 : : {
483 : 0 : printUnknownCommand(out, "get-interpolant-next");
484 : 0 : }
485 : :
486 : 0 : void Printer::toStreamCmdGetAbduct(std::ostream& out,
487 : : const std::string& name,
488 : : Node conj,
489 : : TypeNode sygusType) const
490 : : {
491 : 0 : printUnknownCommand(out, "get-abduct");
492 : 0 : }
493 : :
494 : 0 : void Printer::toStreamCmdGetAbductNext(std::ostream& out) const
495 : : {
496 : 0 : printUnknownCommand(out, "get-abduct-next");
497 : 0 : }
498 : :
499 : 0 : void Printer::toStreamCmdGetQuantifierElimination(std::ostream& out,
500 : : Node n,
501 : : bool doFull) const
502 : : {
503 : 0 : printUnknownCommand(out, "get-quantifier-elimination");
504 : 0 : }
505 : :
506 : 0 : void Printer::toStreamCmdGetUnsatAssumptions(std::ostream& out) const
507 : : {
508 : 0 : printUnknownCommand(out, "get-unsat-assumption");
509 : 0 : }
510 : :
511 : 0 : void Printer::toStreamCmdGetUnsatCore(std::ostream& out) const
512 : : {
513 : 0 : printUnknownCommand(out, "get-unsat-core");
514 : 0 : }
515 : :
516 : 0 : void Printer::toStreamCmdGetDifficulty(std::ostream& out) const
517 : : {
518 : 0 : printUnknownCommand(out, "get-difficulty");
519 : 0 : }
520 : :
521 : 0 : void Printer::toStreamCmdGetTimeoutCore(std::ostream& out) const
522 : : {
523 : 0 : printUnknownCommand(out, "get-timeout-core");
524 : 0 : }
525 : :
526 : 0 : void Printer::toStreamCmdGetTimeoutCoreAssuming(
527 : : std::ostream& out, const std::vector<Node>& assumptions) const
528 : : {
529 : 0 : printUnknownCommand(out, "get-timeout-core-assuming");
530 : 0 : }
531 : :
532 : 0 : void Printer::toStreamCmdGetLearnedLiterals(std::ostream& out,
533 : : modes::LearnedLitType t) const
534 : : {
535 : 0 : printUnknownCommand(out, "get-learned-literals");
536 : 0 : }
537 : :
538 : 0 : void Printer::toStreamCmdGetAssertions(std::ostream& out) const
539 : : {
540 : 0 : printUnknownCommand(out, "get-assertions");
541 : 0 : }
542 : :
543 : 0 : void Printer::toStreamCmdSetBenchmarkLogic(std::ostream& out,
544 : : const std::string& logic) const
545 : : {
546 : 0 : printUnknownCommand(out, "set-logic");
547 : 0 : }
548 : :
549 : 0 : void Printer::toStreamCmdSetInfo(std::ostream& out,
550 : : const std::string& flag,
551 : : const std::string& value) const
552 : : {
553 : 0 : printUnknownCommand(out, "set-info");
554 : 0 : }
555 : :
556 : 0 : void Printer::toStreamCmdGetInfo(std::ostream& out,
557 : : const std::string& flag) const
558 : : {
559 : 0 : printUnknownCommand(out, "get-info");
560 : 0 : }
561 : :
562 : 0 : void Printer::toStreamCmdSetOption(std::ostream& out,
563 : : const std::string& flag,
564 : : const std::string& value) const
565 : : {
566 : 0 : printUnknownCommand(out, "set-option");
567 : 0 : }
568 : :
569 : 0 : void Printer::toStreamCmdGetOption(std::ostream& out,
570 : : const std::string& flag) const
571 : : {
572 : 0 : printUnknownCommand(out, "get-option");
573 : 0 : }
574 : :
575 : 0 : void Printer::toStreamCmdSetExpressionName(std::ostream& out,
576 : : Node n,
577 : : const std::string& name) const
578 : : {
579 : 0 : printUnknownCommand(out, "set-expression-name");
580 : 0 : }
581 : :
582 : 0 : void Printer::toStreamCmdDatatypeDeclaration(
583 : : std::ostream& out, const std::vector<TypeNode>& datatypes) const
584 : : {
585 [ - - ]: 0 : printUnknownCommand(
586 : 0 : out, datatypes.size() == 1 ? "declare-datatype" : "declare-datatypes");
587 : 0 : }
588 : :
589 : 0 : void Printer::toStreamCmdReset(std::ostream& out) const
590 : : {
591 : 0 : printUnknownCommand(out, "reset");
592 : 0 : }
593 : :
594 : 0 : void Printer::toStreamCmdResetAssertions(std::ostream& out) const
595 : : {
596 : 0 : printUnknownCommand(out, "reset-assertions");
597 : 0 : }
598 : :
599 : 0 : void Printer::toStreamCmdQuit(std::ostream& out) const
600 : : {
601 : 0 : printUnknownCommand(out, "quit");
602 : 0 : }
603 : :
604 : 0 : void Printer::toStreamCmdDeclareHeap(std::ostream& out,
605 : : TypeNode locType,
606 : : TypeNode dataType) const
607 : : {
608 : 0 : printUnknownCommand(out, "declare-heap");
609 : 0 : }
610 : :
611 : : } // namespace cvc5::internal
|