1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1999-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/btree.h"
14#include "dbinc/qam.h"
15
16static int __bam_set_bt_minkey __P((DB *, u_int32_t));
17static int __bam_get_bt_compare
18	       __P((DB *, int (**)(DB *, const DBT *, const DBT *)));
19static int __bam_get_bt_prefix
20	       __P((DB *, size_t(**)(DB *, const DBT *, const DBT *)));
21static int __bam_set_bt_prefix
22	       __P((DB *, size_t(*)(DB *, const DBT *, const DBT *)));
23static int __bam_get_bt_compress __P((DB *,
24    int (**)(DB *, const DBT *, const DBT *, const DBT *, const DBT *, DBT *),
25    int (**)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *)));
26static int __ram_get_re_delim __P((DB *, int *));
27static int __ram_set_re_delim __P((DB *, int));
28static int __ram_set_re_len __P((DB *, u_int32_t));
29static int __ram_set_re_pad __P((DB *, int));
30static int __ram_get_re_source __P((DB *, const char **));
31static int __ram_set_re_source __P((DB *, const char *));
32
33/*
34 * __bam_db_create --
35 *	Btree specific initialization of the DB structure.
36 *
37 * PUBLIC: int __bam_db_create __P((DB *));
38 */
39int
40__bam_db_create(dbp)
41	DB *dbp;
42{
43	BTREE *t;
44	int ret;
45
46	/* Allocate and initialize the private btree structure. */
47	if ((ret = __os_calloc(dbp->env, 1, sizeof(BTREE), &t)) != 0)
48		return (ret);
49	dbp->bt_internal = t;
50
51	t->bt_minkey = DEFMINKEYPAGE;		/* Btree */
52	t->bt_compare = __bam_defcmp;
53	t->bt_prefix = __bam_defpfx;
54#ifdef HAVE_COMPRESSION
55	t->bt_compress = NULL;
56	t->bt_decompress = NULL;
57	t->compress_dup_compare = NULL;
58
59	/*
60	 * DB_AM_COMPRESS may have been set in __bam_metachk before the
61	 * bt_internal structure existed.
62	 */
63	if (F_ISSET(dbp, DB_AM_COMPRESS) &&
64	    (ret = __bam_set_bt_compress(dbp, NULL, NULL)) != 0)
65		return (ret);
66#endif
67
68	dbp->get_bt_compare = __bam_get_bt_compare;
69	dbp->set_bt_compare = __bam_set_bt_compare;
70	dbp->get_bt_minkey = __bam_get_bt_minkey;
71	dbp->set_bt_minkey = __bam_set_bt_minkey;
72	dbp->get_bt_prefix = __bam_get_bt_prefix;
73	dbp->set_bt_prefix = __bam_set_bt_prefix;
74	dbp->get_bt_compress = __bam_get_bt_compress;
75	dbp->set_bt_compress = __bam_set_bt_compress;
76
77	t->re_pad = ' ';			/* Recno */
78	t->re_delim = '\n';
79	t->re_eof = 1;
80
81	dbp->get_re_delim = __ram_get_re_delim;
82	dbp->set_re_delim = __ram_set_re_delim;
83	dbp->get_re_len = __ram_get_re_len;
84	dbp->set_re_len = __ram_set_re_len;
85	dbp->get_re_pad = __ram_get_re_pad;
86	dbp->set_re_pad = __ram_set_re_pad;
87	dbp->get_re_source = __ram_get_re_source;
88	dbp->set_re_source = __ram_set_re_source;
89
90	return (0);
91}
92
93/*
94 * __bam_db_close --
95 *	Btree specific discard of the DB structure.
96 *
97 * PUBLIC: int __bam_db_close __P((DB *));
98 */
99int
100__bam_db_close(dbp)
101	DB *dbp;
102{
103	BTREE *t;
104
105	if ((t = dbp->bt_internal) == NULL)
106		return (0);
107						/* Recno */
108	/* Close any backing source file descriptor. */
109	if (t->re_fp != NULL)
110		(void)fclose(t->re_fp);
111
112	/* Free any backing source file name. */
113	if (t->re_source != NULL)
114		__os_free(dbp->env, t->re_source);
115
116	__os_free(dbp->env, t);
117	dbp->bt_internal = NULL;
118
119	return (0);
120}
121
122/*
123 * __bam_map_flags --
124 *	Map Btree specific flags from public to the internal values.
125 *
126 * PUBLIC: void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *));
127 */
128void
129__bam_map_flags(dbp, inflagsp, outflagsp)
130	DB *dbp;
131	u_int32_t *inflagsp, *outflagsp;
132{
133	COMPQUIET(dbp, NULL);
134
135	if (FLD_ISSET(*inflagsp, DB_DUP)) {
136		FLD_SET(*outflagsp, DB_AM_DUP);
137		FLD_CLR(*inflagsp, DB_DUP);
138	}
139	if (FLD_ISSET(*inflagsp, DB_DUPSORT)) {
140		FLD_SET(*outflagsp, DB_AM_DUP | DB_AM_DUPSORT);
141		FLD_CLR(*inflagsp, DB_DUPSORT);
142	}
143	if (FLD_ISSET(*inflagsp, DB_RECNUM)) {
144		FLD_SET(*outflagsp, DB_AM_RECNUM);
145		FLD_CLR(*inflagsp, DB_RECNUM);
146	}
147	if (FLD_ISSET(*inflagsp, DB_REVSPLITOFF)) {
148		FLD_SET(*outflagsp, DB_AM_REVSPLITOFF);
149		FLD_CLR(*inflagsp, DB_REVSPLITOFF);
150	}
151}
152
153/*
154 * __bam_set_flags --
155 *	Set Btree specific flags.
156 *
157 * PUBLIC: int __bam_set_flags __P((DB *, u_int32_t *flagsp));
158 */
159int
160__bam_set_flags(dbp, flagsp)
161	DB *dbp;
162	u_int32_t *flagsp;
163{
164	BTREE *t;
165	u_int32_t flags;
166
167	t = dbp->bt_internal;
168
169	flags = *flagsp;
170	if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF))
171		DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
172
173	/*
174	 * The DB_DUP and DB_DUPSORT flags are shared by the Hash
175	 * and Btree access methods.
176	 */
177	if (LF_ISSET(DB_DUP | DB_DUPSORT))
178		DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH);
179
180	if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF))
181		DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
182
183	/* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */
184	if (LF_ISSET(DB_DUP | DB_DUPSORT) && F_ISSET(dbp, DB_AM_RECNUM))
185		goto incompat;
186
187	/* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */
188	if (LF_ISSET(DB_RECNUM) && F_ISSET(dbp, DB_AM_DUP))
189		goto incompat;
190
191	/* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */
192	if (LF_ISSET(DB_RECNUM) && LF_ISSET(DB_DUP | DB_DUPSORT))
193		goto incompat;
194
195#ifdef HAVE_COMPRESSION
196	/* DB_RECNUM is incompatible with compression */
197	if (LF_ISSET(DB_RECNUM) && DB_IS_COMPRESSED(dbp)) {
198		__db_errx(dbp->env,
199		    "DB_RECNUM cannot be used with compression");
200		return (EINVAL);
201	}
202
203	/* DB_DUP without DB_DUPSORT is incompatible with compression */
204	if (LF_ISSET(DB_DUP) && !LF_ISSET(DB_DUPSORT) &&
205		!F_ISSET(dbp, DB_AM_DUPSORT) && DB_IS_COMPRESSED(dbp)) {
206		__db_errx(dbp->env,
207		   "DB_DUP cannot be used with compression without DB_DUPSORT");
208		return (EINVAL);
209	}
210#endif
211
212	if (LF_ISSET(DB_DUPSORT) && dbp->dup_compare == NULL) {
213#ifdef HAVE_COMPRESSION
214		if (DB_IS_COMPRESSED(dbp)) {
215			dbp->dup_compare = __bam_compress_dupcmp;
216			t->compress_dup_compare = __bam_defcmp;
217		} else
218#endif
219			dbp->dup_compare = __bam_defcmp;
220	}
221
222	__bam_map_flags(dbp, flagsp, &dbp->flags);
223	return (0);
224
225incompat:
226	return (__db_ferr(dbp->env, "DB->set_flags", 1));
227}
228
229/*
230 * __bam_get_bt_compare --
231 *	Get the comparison function.
232 */
233static int
234__bam_get_bt_compare(dbp, funcp)
235	DB *dbp;
236	int (**funcp) __P((DB *, const DBT *, const DBT *));
237{
238	BTREE *t;
239
240	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
241
242	t = dbp->bt_internal;
243
244	if (funcp != NULL)
245		*funcp = t->bt_compare;
246
247	return (0);
248}
249
250/*
251 * __bam_set_bt_compare --
252 *	Set the comparison function.
253 *
254 * PUBLIC: int __bam_set_bt_compare
255 * PUBLIC:         __P((DB *, int (*)(DB *, const DBT *, const DBT *)));
256 */
257int
258__bam_set_bt_compare(dbp, func)
259	DB *dbp;
260	int (*func) __P((DB *, const DBT *, const DBT *));
261{
262	BTREE *t;
263
264	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compare");
265	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
266
267	t = dbp->bt_internal;
268
269	/*
270	 * Can't default the prefix routine if the user supplies a comparison
271	 * routine; shortening the keys can break their comparison algorithm.
272	 */
273	t->bt_compare = func;
274	if (t->bt_prefix == __bam_defpfx)
275		t->bt_prefix = NULL;
276
277	return (0);
278}
279
280/*
281 * __bam_get_bt_compress --
282 *	Get the compression functions.
283 */
284static int
285__bam_get_bt_compress(dbp, compressp, decompressp)
286	DB *dbp;
287	int (**compressp) __P((DB *, const DBT *, const DBT *, const DBT *,
288				      const DBT *, DBT *));
289	int (**decompressp) __P((DB *, const DBT *, const DBT *, DBT *, DBT *,
290					DBT *));
291{
292#ifdef HAVE_COMPRESSION
293	BTREE *t;
294
295	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
296
297	t = dbp->bt_internal;
298
299	if (compressp != NULL)
300		*compressp = t->bt_compress;
301	if (decompressp != NULL)
302		*decompressp = t->bt_decompress;
303
304	return (0);
305#else
306	COMPQUIET(compressp, NULL);
307	COMPQUIET(decompressp, NULL);
308
309	__db_errx(dbp->env, "compression support has not been compiled in");
310	return (EINVAL);
311#endif
312}
313
314/*
315 * __bam_set_bt_compress --
316 *	Set the compression functions.
317 *
318 * PUBLIC: int __bam_set_bt_compress __P((DB *,
319 * PUBLIC:  int (*)(DB *, const DBT *, const DBT *,
320 * PUBLIC:	    const DBT *, const DBT *, DBT *),
321 * PUBLIC:  int (*)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *)));
322 */
323int
324__bam_set_bt_compress(dbp, compress, decompress)
325	DB *dbp;
326	int (*compress) __P((DB *, const DBT *, const DBT *, const DBT *,
327				    const DBT *, DBT *));
328	int (*decompress) __P((DB *, const DBT *, const DBT *, DBT *, DBT *,
329				      DBT *));
330{
331#ifdef HAVE_COMPRESSION
332	BTREE *t;
333
334	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compress");
335	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
336
337	t = dbp->bt_internal;
338
339	/* compression is incompatible with DB_RECNUM */
340	if (F_ISSET(dbp, DB_AM_RECNUM)) {
341		__db_errx(dbp->env,
342		    "compression cannot be used with DB_RECNUM");
343		return (EINVAL);
344	}
345
346	/* compression is incompatible with DB_DUP without DB_DUPSORT */
347	if (F_ISSET(dbp, DB_AM_DUP) && !F_ISSET(dbp, DB_AM_DUPSORT)) {
348		__db_errx(dbp->env,
349		   "compression cannot be used with DB_DUP without DB_DUPSORT");
350		return (EINVAL);
351	}
352
353	if (compress != 0 && decompress != 0) {
354		t->bt_compress = compress;
355		t->bt_decompress = decompress;
356	} else if (compress == 0 && decompress == 0) {
357		t->bt_compress = __bam_defcompress;
358		t->bt_decompress = __bam_defdecompress;
359	} else {
360		__db_errx(dbp->env,
361	    "to enable compression you need to supply both function arguments");
362		return (EINVAL);
363	}
364	F_SET(dbp, DB_AM_COMPRESS);
365
366	/* Copy dup_compare to compress_dup_compare, and use the compression
367	   duplicate compare */
368	if (F_ISSET(dbp, DB_AM_DUPSORT)) {
369		t->compress_dup_compare = dbp->dup_compare;
370		dbp->dup_compare = __bam_compress_dupcmp;
371	}
372
373	return (0);
374#else
375	COMPQUIET(compress, NULL);
376	COMPQUIET(decompress, NULL);
377
378	__db_errx(dbp->env, "compression support has not been compiled in");
379	return (EINVAL);
380#endif
381}
382
383/*
384 * __db_get_bt_minkey --
385 *	Get the minimum keys per page.
386 *
387 * PUBLIC: int __bam_get_bt_minkey __P((DB *, u_int32_t *));
388 */
389int
390__bam_get_bt_minkey(dbp, bt_minkeyp)
391	DB *dbp;
392	u_int32_t *bt_minkeyp;
393{
394	BTREE *t;
395
396	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
397
398	t = dbp->bt_internal;
399	*bt_minkeyp = t->bt_minkey;
400	return (0);
401}
402
403/*
404 * __bam_set_bt_minkey --
405 *	Set the minimum keys per page.
406 */
407static int
408__bam_set_bt_minkey(dbp, bt_minkey)
409	DB *dbp;
410	u_int32_t bt_minkey;
411{
412	BTREE *t;
413
414	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_minkey");
415	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
416
417	t = dbp->bt_internal;
418
419	if (bt_minkey < 2) {
420		__db_errx(dbp->env, "minimum bt_minkey value is 2");
421		return (EINVAL);
422	}
423
424	t->bt_minkey = bt_minkey;
425	return (0);
426}
427
428/*
429 * __bam_get_bt_prefix --
430 *	Get the prefix function.
431 */
432static int
433__bam_get_bt_prefix(dbp, funcp)
434	DB *dbp;
435	size_t (**funcp) __P((DB *, const DBT *, const DBT *));
436{
437	BTREE *t;
438
439	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
440
441	t = dbp->bt_internal;
442	if (funcp != NULL)
443		*funcp = t->bt_prefix;
444	return (0);
445}
446
447/*
448 * __bam_set_bt_prefix --
449 *	Set the prefix function.
450 */
451static int
452__bam_set_bt_prefix(dbp, func)
453	DB *dbp;
454	size_t (*func) __P((DB *, const DBT *, const DBT *));
455{
456	BTREE *t;
457
458	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_prefix");
459	DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE);
460
461	t = dbp->bt_internal;
462
463	t->bt_prefix = func;
464	return (0);
465}
466
467/*
468 * __bam_copy_config
469 *	Copy the configuration of one DB handle to another.
470 * PUBLIC: void __bam_copy_config __P((DB *, DB*, u_int32_t));
471 */
472void
473__bam_copy_config(src, dst, nparts)
474	DB *src, *dst;
475	u_int32_t nparts;
476{
477	BTREE *s, *d;
478
479	COMPQUIET(nparts, 0);
480
481	s = src->bt_internal;
482	d = dst->bt_internal;
483	d->bt_compare = s->bt_compare;
484	d->bt_minkey = s->bt_minkey;
485	d->bt_minkey = s->bt_minkey;
486	d->bt_prefix = s->bt_prefix;
487#ifdef HAVE_COMPRESSION
488	d->bt_compress = s->bt_compress;
489	d->bt_decompress = s->bt_decompress;
490	d->compress_dup_compare = s->compress_dup_compare;
491#endif
492}
493
494/*
495 * __ram_map_flags --
496 *	Map Recno specific flags from public to the internal values.
497 *
498 * PUBLIC: void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *));
499 */
500void
501__ram_map_flags(dbp, inflagsp, outflagsp)
502	DB *dbp;
503	u_int32_t *inflagsp, *outflagsp;
504{
505	COMPQUIET(dbp, NULL);
506
507	if (FLD_ISSET(*inflagsp, DB_RENUMBER)) {
508		FLD_SET(*outflagsp, DB_AM_RENUMBER);
509		FLD_CLR(*inflagsp, DB_RENUMBER);
510	}
511	if (FLD_ISSET(*inflagsp, DB_SNAPSHOT)) {
512		FLD_SET(*outflagsp, DB_AM_SNAPSHOT);
513		FLD_CLR(*inflagsp, DB_SNAPSHOT);
514	}
515}
516
517/*
518 * __ram_set_flags --
519 *	Set Recno specific flags.
520 *
521 * PUBLIC: int __ram_set_flags __P((DB *, u_int32_t *flagsp));
522 */
523int
524__ram_set_flags(dbp, flagsp)
525	DB *dbp;
526	u_int32_t *flagsp;
527{
528	u_int32_t flags;
529
530	flags = *flagsp;
531	if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) {
532		DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags");
533		DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
534	}
535
536	__ram_map_flags(dbp, flagsp, &dbp->flags);
537	return (0);
538}
539
540/*
541 * __db_get_re_delim --
542 *	Get the variable-length input record delimiter.
543 */
544static int
545__ram_get_re_delim(dbp, re_delimp)
546	DB *dbp;
547	int *re_delimp;
548{
549	BTREE *t;
550
551	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
552	t = dbp->bt_internal;
553	*re_delimp = t->re_delim;
554	return (0);
555}
556
557/*
558 * __ram_set_re_delim --
559 *	Set the variable-length input record delimiter.
560 */
561static int
562__ram_set_re_delim(dbp, re_delim)
563	DB *dbp;
564	int re_delim;
565{
566	BTREE *t;
567
568	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_delim");
569	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
570
571	t = dbp->bt_internal;
572
573	t->re_delim = re_delim;
574	F_SET(dbp, DB_AM_DELIMITER);
575
576	return (0);
577}
578
579/*
580 * __db_get_re_len --
581 *	Get the variable-length input record length.
582 *
583 * PUBLIC: int __ram_get_re_len __P((DB *, u_int32_t *));
584 */
585int
586__ram_get_re_len(dbp, re_lenp)
587	DB *dbp;
588	u_int32_t *re_lenp;
589{
590	BTREE *t;
591	QUEUE *q;
592
593	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
594
595	/*
596	 * This has to work for all access methods, before or after opening the
597	 * database.  When the record length is set with __ram_set_re_len, the
598	 * value in both the BTREE and QUEUE structs will be correct.
599	 * Otherwise, this only makes sense after the database in opened, in
600	 * which case we know the type.
601	 */
602	if (dbp->type == DB_QUEUE) {
603		q = dbp->q_internal;
604		*re_lenp = q->re_len;
605	} else {
606		t = dbp->bt_internal;
607		*re_lenp = t->re_len;
608	}
609
610	return (0);
611}
612
613/*
614 * __ram_set_re_len --
615 *	Set the variable-length input record length.
616 */
617static int
618__ram_set_re_len(dbp, re_len)
619	DB *dbp;
620	u_int32_t re_len;
621{
622	BTREE *t;
623	QUEUE *q;
624
625	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_len");
626	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
627
628	t = dbp->bt_internal;
629	t->re_len = re_len;
630
631	q = dbp->q_internal;
632	q->re_len = re_len;
633
634	F_SET(dbp, DB_AM_FIXEDLEN);
635
636	return (0);
637}
638
639/*
640 * __db_get_re_pad --
641 *	Get the fixed-length record pad character.
642 *
643 * PUBLIC: int __ram_get_re_pad __P((DB *, int *));
644 */
645int
646__ram_get_re_pad(dbp, re_padp)
647	DB *dbp;
648	int *re_padp;
649{
650	BTREE *t;
651	QUEUE *q;
652
653	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
654
655	/*
656	 * This has to work for all access methods, before or after opening the
657	 * database.  When the record length is set with __ram_set_re_pad, the
658	 * value in both the BTREE and QUEUE structs will be correct.
659	 * Otherwise, this only makes sense after the database in opened, in
660	 * which case we know the type.
661	 */
662	if (dbp->type == DB_QUEUE) {
663		q = dbp->q_internal;
664		*re_padp = q->re_pad;
665	} else {
666		t = dbp->bt_internal;
667		*re_padp = t->re_pad;
668	}
669
670	return (0);
671}
672
673/*
674 * __ram_set_re_pad --
675 *	Set the fixed-length record pad character.
676 */
677static int
678__ram_set_re_pad(dbp, re_pad)
679	DB *dbp;
680	int re_pad;
681{
682	BTREE *t;
683	QUEUE *q;
684
685	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_pad");
686	DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO);
687
688	t = dbp->bt_internal;
689	t->re_pad = re_pad;
690
691	q = dbp->q_internal;
692	q->re_pad = re_pad;
693
694	F_SET(dbp, DB_AM_PAD);
695
696	return (0);
697}
698
699/*
700 * __db_get_re_source --
701 *	Get the backing source file name.
702 */
703static int
704__ram_get_re_source(dbp, re_sourcep)
705	DB *dbp;
706	const char **re_sourcep;
707{
708	BTREE *t;
709
710	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
711
712	t = dbp->bt_internal;
713	*re_sourcep = t->re_source;
714	return (0);
715}
716
717/*
718 * __ram_set_re_source --
719 *	Set the backing source file name.
720 */
721static int
722__ram_set_re_source(dbp, re_source)
723	DB *dbp;
724	const char *re_source;
725{
726	BTREE *t;
727
728	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_source");
729	DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO);
730
731	t = dbp->bt_internal;
732
733	return (__os_strdup(dbp->env, re_source, &t->re_source));
734}
735