Thread: [Goom] patch from goom integration into xine
Brought to you by:
jchoelt
From: Michael R. <mr...@us...> - 2004-06-27 12:22:46
Attachments:
xine-goom-fixes.patch
|
Hi goom team, I hope this is the right list for my mail. If not, please tell me, where to turn to. This is Michael Roitzsch from the xine team. As you might know, xine is using goom to present those nifty effects of yours for audio-only files. Since it is our policy to make installation easy for the user, we included a copy of the goom code into xine-lib. Unfortunately, this copy received some patches and fixes and was starting to drift from the original version, making future merges of new goom releases more difficult. To resolve this, I decided to include the current goom2k4-dev15 into xine-lib and ported all the patches to this new version. Now I would like to ask, if some, maybe even all of these changes could be applied to your official goom tree. I attached a patch containing all our changes to far. It fixes three things: * make goom silent This is the biggest and probably most unimportant part of the patch. It wraps those printfs I saw when running goom in xine, because xine-lib should be silent on the console. This part of the patch might be a problem, because some of the files I modified appear to be the output of flex/bison, so one actually has to patch the input files to these tools. But since I know next to nothing about flex/bison (I know just enough to avoid it... ;) ), I did not try that. * fix goom on AMD64 On several occasions, goom casts pointers to int. This is bad, because it breaks AMD64 and other 64 bit platforms. We fixed these by using a C99 inttype. * fix a memleak The free_ifs() added in ifs.c fixes a memory leak. If there is a chance that this patch could find its way into the official tree, I would like to start work on yet another patch: Goom compilation inside xine-lib emits quite a lot of compiler warnings which I would like to fix. Michael -- "Unix? What's that? Is that like Linux?" |
From: Jean-Christophe <je...@io...> - 2004-06-29 09:23:00
|
I applied your patch which worked. The flex/bison changes will not be kept anyway: files to edit are goom_script_scanner.lex / .yacc If you open them, you will see that it's mainly C code. If some small things need to be made inside #ifdef XINE #endif Dont hesitate to submit a patch for that as well, so that your job will be easier. I'll put a new tarball with your changes online soon, I added support for sub-functions in the embedded scripting language of goom: so I've just a few things to finish there before. Regards, Jeko Michael Roitzsch wrote: >Hi goom team, > >I hope this is the right list for my mail. If not, please tell me, where to >turn to. > >This is Michael Roitzsch from the xine team. As you might know, xine is using >goom to present those nifty effects of yours for audio-only files. Since it >is our policy to make installation easy for the user, we included a copy of >the goom code into xine-lib. Unfortunately, this copy received some patches >and fixes and was starting to drift from the original version, making future >merges of new goom releases more difficult. To resolve this, I decided to >include the current goom2k4-dev15 into xine-lib and ported all the patches to >this new version. > >Now I would like to ask, if some, maybe even all of these changes could be >applied to your official goom tree. I attached a patch containing all our >changes to far. It fixes three things: >* make goom silent > This is the biggest and probably most unimportant part of the patch. It > wraps those printfs I saw when running goom in xine, because xine-lib should > be silent on the console. > This part of the patch might be a problem, because some of the files I > modified appear to be the output of flex/bison, so one actually has to patch > the input files to these tools. But since I know next to nothing about > flex/bison (I know just enough to avoid it... ;) ), I did not try that. >* fix goom on AMD64 > On several occasions, goom casts pointers to int. This is bad, because it > breaks AMD64 and other 64 bit platforms. We fixed these by using a C99 > inttype. >* fix a memleak > The free_ifs() added in ifs.c fixes a memory leak. > >If there is a chance that this patch could find its way into the official >tree, I would like to start work on yet another patch: Goom compilation >inside xine-lib emits quite a lot of compiler warnings which I would like to >fix. > >Michael > > > >------------------------------------------------------------------------ > >--- config_param.c 2004-06-20 15:07:37.000000000 +0200 >+++ config_param.c 2004-06-20 14:42:31.000000000 +0200 >@@ -96,7 +96,9 @@ > > void set_list_param_value(PluginParam *p, const char *str) { > int len = strlen(str); >+#ifdef VERBOSE > printf("%s: %d\n", str, len); >+#endif > if (LVAL(*p)) > LVAL(*p) = (char*)realloc(LVAL(*p), len+1); > else >--- convolve_fx.c 2004-06-20 15:07:37.000000000 +0200 >+++ convolve_fx.c 2004-06-20 14:42:54.000000000 +0200 >@@ -104,7 +104,9 @@ > iff = (unsigned int)(ff * 256); > > if (!goom_script_scanner_is_compiled(data->script)) { >+#ifdef VERBOSE > printf("setting default script for dynamic brightness\n"); >+#endif > goom_script_scanner_compile(data->script, info, DEF_SCRIPT); > } > >--- filters.c 2004-03-27 18:15:05.000000000 +0100 >+++ filters.c 2004-06-20 15:16:20.000000000 +0200 >@@ -18,6 +18,7 @@ > #include <stdlib.h> > #include <math.h> > #include <stdio.h> >+#include <inttypes.h> > > #include "goom_filters.h" > #include "goom_graphic.h" >@@ -571,13 +572,13 @@ > > data->mustInitBuffers = 0; > data->freebrutS = (signed int *) calloc (resx * resy * 2 + 128, sizeof(unsigned int)); >- data->brutS = (gint32 *) ((1 + ((unsigned int) (data->freebrutS)) / 128) * 128); >+ data->brutS = (gint32 *) ((1 + ((uintptr_t) (data->freebrutS)) / 128) * 128); > > data->freebrutD = (signed int *) calloc (resx * resy * 2 + 128, sizeof(unsigned int)); >- data->brutD = (gint32 *) ((1 + ((unsigned int) (data->freebrutD)) / 128) * 128); >+ data->brutD = (gint32 *) ((1 + ((uintptr_t) (data->freebrutD)) / 128) * 128); > > data->freebrutT = (signed int *) calloc (resx * resy * 2 + 128, sizeof(unsigned int)); >- data->brutT = (gint32 *) ((1 + ((unsigned int) (data->freebrutT)) / 128) * 128); >+ data->brutT = (gint32 *) ((1 + ((uintptr_t) (data->freebrutT)) / 128) * 128); > > data->buffratio = 0; > >--- goom_core.c 2004-03-27 18:15:05.000000000 +0100 >+++ goom_core.c 2004-06-20 15:16:41.000000000 +0200 >@@ -11,6 +11,7 @@ > #include <stdio.h> > #include <stdlib.h> > #include <string.h> >+#include <inttypes.h> > > #include "goom.h" > #include "goom_tools.h" >@@ -45,8 +46,8 @@ > goomInfo->conv = (Pixel *) malloc (buffsize * sizeof (guint32) + 128); > bzero (goomInfo->conv, buffsize * sizeof (guint32) + 128); > >- goomInfo->p1 = (Pixel *) ((1 + ((unsigned int) (goomInfo->pixel)) / 128) * 128); >- goomInfo->p2 = (Pixel *) ((1 + ((unsigned int) (goomInfo->back)) / 128) * 128); >+ goomInfo->p1 = (Pixel *) ((1 + ((uintptr_t) (goomInfo->pixel)) / 128) * 128); >+ goomInfo->p2 = (Pixel *) ((1 + ((uintptr_t) (goomInfo->back)) / 128) * 128); > } > > /************************** >@@ -84,7 +85,7 @@ > goomInfo->screen.size = resx * resy; > > init_buffers(goomInfo, goomInfo->screen.size); >- goomInfo->gRandom = goom_random_init((guint32)goomInfo->pixel); >+ goomInfo->gRandom = goom_random_init((uintptr_t)goomInfo->pixel); > > goomInfo->cycle = 0; > >--- goom_script_scanner.c 2004-06-20 15:07:37.000000000 +0200 >+++ goom_script_scanner.c 2004-06-20 14:45:07.000000000 +0200 >@@ -2412,7 +2412,9 @@ > > void goom_script_scanner_compile(GoomScriptScanner *_currentScanner, PluginInfo *pluginInfo, const char *script) { > >+#ifdef VERBOSE > printf("\n=== Starting Compilation ===\n"); >+#endif > currentScanner = _currentScanner; > reset_scanner(currentScanner); > currentScanner->pluginInfo = pluginInfo; >@@ -2423,7 +2425,9 @@ > > calculate_labels(currentScanner->iflow); > >+#ifdef VERBOSE > printf("=== Compilation done. # of lines: %d. # of instr: %d ===\n", currentScanner->num_lines, currentScanner->iflow->number); >+#endif > } > > void goom_script_scanner_execute(GoomScriptScanner *scanner) { >--- goom_script_scanner.tab.c 2004-06-20 15:07:37.000000000 +0200 >+++ goom_script_scanner.tab.c 2004-06-20 14:50:07.000000000 +0200 >@@ -108,7 +108,9 @@ > } > static void commit_set(NodeType *set) { > precommit_node(set->opr.op[1]); >+#ifdef VERBOSE > printf("set.f %s %s\n", set->opr.op[0]->str, set->opr.op[1]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "set.f", INSTR_SETF, 2); > commit_node(set->opr.op[0]); > commit_node(set->opr.op[1]); >@@ -121,7 +123,9 @@ > return fld; > } > static void commit_float(NodeType *var) { >+#ifdef VERBOSE > printf("float %s\n", var->opr.op[0]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "float", INSTR_INT, 1); > commit_node(var->opr.op[0]); > } >@@ -133,7 +137,9 @@ > return intd; > } > static void commit_int(NodeType *var) { >+#ifdef VERBOSE > printf("int %s\n", var->opr.op[0]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "int", INSTR_INT, 1); > commit_node(var->opr.op[0]); > } >@@ -172,7 +178,9 @@ > } > > /* add op2 to tmp */ >+#ifdef VERBOSE > printf("%s %s %s\n", type, stmp, expr->opr.op[toAdd]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, type, instr_id, 2); > commit_node(new_var(stmp)); > commit_node(expr->opr.op[toAdd]); >@@ -237,7 +245,9 @@ > > /* jzero.i <expression> <endif> */ > sprintf(slab, "|eif%d|", allocateLabel()); >+#ifdef VERBOSE > printf("jzero.i %s %s\n", node->opr.op[0]->str, slab); >+#endif > currentScanner->instr = instr_init(currentScanner, "jzero.i", INSTR_JZERO, 2); > commit_node(node->opr.op[0]); > instr_add_param(currentScanner->instr, slab, TYPE_LABEL); >@@ -245,7 +255,9 @@ > /* [... instrs of the if ...] */ > commit_node(node->opr.op[1]); > /* label <endif> */ >+#ifdef VERBOSE > printf("label %s\n", slab); >+#endif > currentScanner->instr = instr_init(currentScanner, "label", INSTR_LABEL, 1); > instr_add_param(currentScanner->instr, slab, TYPE_LABEL); > } >@@ -315,7 +327,9 @@ > case OPR_SET: commit_set(node); break; > case OPR_IF: commit_if(node); break; > case OPR_BLOCK: commit_block(node); break; >+#ifdef VERBOSE > case EMPTY_NODE: printf("NOP\n"); break; >+#endif > } > > commit_node(node->opr.next); /* recursive for the moment, maybe better to do something iterative? */ >--- ifs.c 2004-03-27 18:15:05.000000000 +0100 >+++ ifs.c 2004-06-20 15:19:09.000000000 +0200 >@@ -454,6 +454,7 @@ > static void release_ifs (IfsData *data) > { > if (data->Root != NULL) { >+ free_ifs (data->Root); > (void) free ((void *) data->Root); > data->Root = (FRACTAL *) NULL; > } >--- plugin_info.c 2004-06-20 15:07:37.000000000 +0200 >+++ plugin_info.c 2004-06-20 14:51:22.000000000 +0200 >@@ -44,17 +44,23 @@ > > #ifdef CPU_X86 > if (cpuFlavour & CPU_OPTION_XMMX) { >+#ifdef VERBOSE > printf ("Extented MMX detected. Using the fastest methods !\n"); >+#endif > p->methods.draw_line = draw_line_mmx; > p->methods.zoom_filter = zoom_filter_xmmx; > } > else if (cpuFlavour & CPU_OPTION_MMX) { >+#ifdef VERBOSE > printf ("MMX detected. Using fast methods !\n"); >+#endif > p->methods.draw_line = draw_line_mmx; > p->methods.zoom_filter = zoom_filter_mmx; > } >+#ifdef VERBOSE > else > printf ("Too bad ! No SIMD optimization available for your CPU.\n"); >+#endif > #endif /* CPU_X86 */ > > #ifdef CPU_POWERPC > > |
From: Michael R. <mr...@us...> - 2004-07-01 19:58:41
Attachments:
xine-goom-fixes2.patch
|
Hi Jeko, > I applied your patch which worked. Thanks a lot. :) > The flex/bison changes will not be kept anyway: files to edit are > goom_script_scanner.lex / .yacc If you open them, you will see that it's > mainly C code. I see. The attached patch should port my changes to these files. Is that ok? I am afraid this won't be the last patch. New changes will arrive here shortly. There is one other thing a couple of xine developers noticed: goom2k4 always starts with the same effect, no matter what file xine plays. It is a circular wave visualization that washes out to all white, stays almost totally white for a while, which looks a bit strange, before moving on to the next effect. Could there be some problem with random initialization? > I'll put a new tarball with your changes online soon, I added support > for sub-functions in the embedded scripting language of goom: so I've > just a few things to finish there before. Btw, is there a public CVS of goom somewhere? Michael -- I am Bill of Borg. Resistance izkx GPF 0x5654 8820 Application RESIST.EXE has performed an illegal operation and will be shut down. |
From: Guillaume B. <gb...@fr...> - 2004-07-01 20:40:11
|
On Jul 1, 2004, at 12:58 PM, Michael Roitzsch wrote: > Btw, is there a public CVS of goom somewhere? There will be one soon on SourceForge. -Gyom |
From: Jean-Christophe <je...@io...> - 2004-07-01 22:09:34
|
Hi Michael, I applied this patch as well, and uploaded an updated tarball on the website http://www.ios-software.com/index.php3?page=projet&quoi=1&where=goom/devel/index.html in this version you can also see an early-stage function support into the goom scripting language (see the goom control center -> brigh flash). Any other patch are welcome. See ya, Jeko Michael Roitzsch wrote: >Hi Jeko, > > > >>I applied your patch which worked. >> >> > >Thanks a lot. :) > > > >>The flex/bison changes will not be kept anyway: files to edit are >>goom_script_scanner.lex / .yacc If you open them, you will see that it's >>mainly C code. >> >> > >I see. The attached patch should port my changes to these files. Is that ok? > >I am afraid this won't be the last patch. New changes will arrive here >shortly. > >There is one other thing a couple of xine developers noticed: goom2k4 always >starts with the same effect, no matter what file xine plays. It is a circular >wave visualization that washes out to all white, stays almost totally white >for a while, which looks a bit strange, before moving on to the next effect. >Could there be some problem with random initialization? > > > >>I'll put a new tarball with your changes online soon, I added support >>for sub-functions in the embedded scripting language of goom: so I've >>just a few things to finish there before. >> >> > >Btw, is there a public CVS of goom somewhere? > >Michael > > > >------------------------------------------------------------------------ > >--- goom2k4-dev15/src/goom_script_scanner.lex Sa Mär 27 18:15:05 2004 >+++ goom2k4-dev15/src/goom_script_scanner.lex Do Jul 1 13:55:18 2004 >@@ -695,7 +695,9 @@ > > void goom_script_scanner_compile(GoomScriptScanner *_currentScanner, PluginInfo *pluginInfo, const char *script) { > >+#ifdef VERBOSE > printf("\n=== Starting Compilation ===\n"); >+#endif > currentScanner = _currentScanner; > reset_scanner(currentScanner); > currentScanner->pluginInfo = pluginInfo; >@@ -706,7 +708,9 @@ > > calculate_labels(currentScanner->iflow); > >+#ifdef VERBOSE > printf("=== Compilation done. # of lines: %d. # of instr: %d ===\n", currentScanner->num_lines, currentScanner->iflow->number); >+#endif > } > > void goom_script_scanner_execute(GoomScriptScanner *scanner) { >--- goom2k4-dev15/src/goom_script_scanner.y Sa Mär 27 18:15:05 2004 >+++ goom2k4-dev15/src/goom_script_scanner.y Do Jul 1 13:53:22 2004 >@@ -38,7 +38,9 @@ > } > static void commit_set(NodeType *set) { > precommit_node(set->opr.op[1]); >+#ifdef VERBOSE > printf("set.f %s %s\n", set->opr.op[0]->str, set->opr.op[1]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "set.f", INSTR_SETF, 2); > commit_node(set->opr.op[0]); > commit_node(set->opr.op[1]); >@@ -51,7 +53,9 @@ > return fld; > } > static void commit_float(NodeType *var) { >+#ifdef VERBOSE > printf("float %s\n", var->opr.op[0]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "float", INSTR_INT, 1); > commit_node(var->opr.op[0]); > } >@@ -63,7 +67,9 @@ > return intd; > } > static void commit_int(NodeType *var) { >+#ifdef VERBOSE > printf("int %s\n", var->opr.op[0]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, "int", INSTR_INT, 1); > commit_node(var->opr.op[0]); > } >@@ -102,7 +108,9 @@ > } > > /* add op2 to tmp */ >+#ifdef VERBOSE > printf("%s %s %s\n", type, stmp, expr->opr.op[toAdd]->str); >+#endif > currentScanner->instr = instr_init(currentScanner, type, instr_id, 2); > commit_node(new_var(stmp)); > commit_node(expr->opr.op[toAdd]); >@@ -167,7 +175,9 @@ > > /* jzero.i <expression> <endif> */ > sprintf(slab, "|eif%d|", allocateLabel()); >+#ifdef VERBOSE > printf("jzero.i %s %s\n", node->opr.op[0]->str, slab); >+#endif > currentScanner->instr = instr_init(currentScanner, "jzero.i", INSTR_JZERO, 2); > commit_node(node->opr.op[0]); > instr_add_param(currentScanner->instr, slab, TYPE_LABEL); >@@ -175,7 +185,9 @@ > /* [... instrs of the if ...] */ > commit_node(node->opr.op[1]); > /* label <endif> */ >+#ifdef VERBOSE > printf("label %s\n", slab); >+#endif > currentScanner->instr = instr_init(currentScanner, "label", INSTR_LABEL, 1); > instr_add_param(currentScanner->instr, slab, TYPE_LABEL); > } >@@ -245,7 +257,9 @@ > case OPR_SET: commit_set(node); break; > case OPR_IF: commit_if(node); break; > case OPR_BLOCK: commit_block(node); break; >+#ifdef VERBOSE > case EMPTY_NODE: printf("NOP\n"); break; >+#endif > } > > commit_node(node->opr.next); /* recursive for the moment, maybe better to do something iterative? */ > > |
From: Michael R. <mr...@us...> - 2004-07-20 17:08:20
Attachments:
goom-warning-fixes.patch
|
Hi Jeko, > I applied this patch as well, and uploaded an updated tarball on the > website > http://www.ios-software.com/index.php3?page=projet&quoi=1&where=goom/devel/ >index.html in this version you can also see an early-stage function support > into the goom scripting language (see the goom control center -> brigh > flash). Any other patch are welcome. Sorry for the delay, university kept my quite busy the last weeks... So here comes the next patch: This one fixes almost all compiler warnings when compiling goom with the xine-lib CFLAGS. * It adds a lot of "static", which should also help the compiler to optimize more aggressively. * Some function prototypes are moved to different header files, so that the same prototype is available when the function is defined or used. This ensures that the compiler sees any inconsistencies. (It actually happened: The zoom_filter_mmx() and zoom_filter_xmmx() functions were used with a different signature than they were defined with.) * Some functions were declared as name(), but this should be name(void). * We also had to change the NodeType structure in goom_script_scanner.h. Older compilers do not support anonymous unions. This also means changing all the places were this union is used. Ok, enough nitpicking for today. ;) I hope you can use some of this. I tried not to modify any flex/bison generated files, but modified the originating files instead. After fixing all the warnings (just some left which are introduced by flex/bison and are not our problem to fix), there is one last issue: gcc 3.4 does not like some of the inline assembler when compiling with -march=pentium4 -msse2. I will look into this. Michael -- Linux is much like an Indian tent: no Gates, no Windows and Apache inside |
From: Jean-Christophe <je...@fr...> - 2004-07-20 23:29:27
|
Hi Michael, The patch was applied successfuly! (except for the lex/yacc files. Since I'm currently doing many changes in them on a "forked" tree, I think you can wait a bit before making patch for them). I applied by hand the 'anonymous union' patch anyway. Updated tarball (dev18) is now on sourceforge. Regards, JC On Tue, 20 Jul 2004, Michael Roitzsch wrote: > Hi Jeko, > > Sorry for the delay, university kept my quite busy the last weeks... > > So here comes the next patch: This one fixes almost all compiler warnings when > compiling goom with the xine-lib CFLAGS. > * It adds a lot of "static", which should also help the compiler to optimize > more aggressively. > * Some function prototypes are moved to different header files, so that the > same prototype is available when the function is defined or used. This > ensures that the compiler sees any inconsistencies. (It actually happened: > The zoom_filter_mmx() and zoom_filter_xmmx() functions were used with a > different signature than they were defined with.) > * Some functions were declared as name(), but this should be name(void). > * We also had to change the NodeType structure in goom_script_scanner.h. > Older compilers do not support anonymous unions. This also means changing > all the places were this union is used. > > Ok, enough nitpicking for today. ;) > > I hope you can use some of this. I tried not to modify any flex/bison > generated files, but modified the originating files instead. > > After fixing all the warnings (just some left which are introduced by > flex/bison and are not our problem to fix), there is one last issue: > gcc 3.4 does not like some of the inline assembler when compiling with > -march=pentium4 -msse2. I will look into this. > > Michael > > -- > Linux is much like an Indian tent: > no Gates, no Windows and Apache inside > |
From: Michael R. <mr...@us...> - 2004-07-21 14:19:46
|
Hi > The patch was applied successfuly! (except for the lex/yacc files. Since > I'm currently doing many changes in them on a "forked" tree, I think you > can wait a bit before making patch for them). Wow, that was fast! Of course I can wait with the rest of the patch. I have to look into the inline assembler compilation problems anyway. > I applied by hand the 'anonymous union' patch anyway. Thanks. :) And thanks also for renaming the files from goom_script_scanner.tab.[ch] to goom_script_yacc.[ch], because automake will delete *.tab.c on distclean. > Updated tarball (dev18) is now on sourceforge. xine-lib CVS now includes dev18. Thanks. Michael -- "UNIX is an operating system, OS/2 is half an operating system, Windows is a shell, and DOS is a boot partition virus." -Peter H. Coffin |
From: Michael R. <mr...@us...> - 2004-08-19 11:08:20
Attachments:
goom-asm-fixes.patch
|
Hi, > I have to look into the inline assembler compilation problems anyway. Attached is a patch that hopefully fixes all remaining assembler problems. * The #ifdef HAVE_MMX I forgot fixes compilation on non-IA32 systems like PPC. Sorry about that. * The assembler constraints for some MMX commands were wrong. "X" matches anything, so when compiling with newer GCC versions for Pentium4, the compiler tries to use SSE registers there, which fails at the assembler stage. Michael -- printk("CPU[%d]: Sending penguins to jail...",smp_processor_id()); 2.4.8 arch/sparc64/kernel/smp.c |
From: Jean-Christophe <je...@fr...> - 2004-08-19 13:27:02
|
Hi, I applied the patch, it still work at home so it's good. You sent it just at the right time: i planned to release a development snapshot today. So I do it now. [...] That's it! http://www.ios-software.com/index.php3?page=projet&quoi=1&where=goom/devel/index.html for more informations. Thank you very much, Best Regards, JC On Thu, 19 Aug 2004, Michael Roitzsch wrote: > Hi, > >> I have to look into the inline assembler compilation problems anyway. > > Attached is a patch that hopefully fixes all remaining assembler problems. > * The #ifdef HAVE_MMX I forgot fixes compilation on non-IA32 systems like PPC. > Sorry about that. > * The assembler constraints for some MMX commands were wrong. "X" matches > anything, so when compiling with newer GCC versions for Pentium4, the > compiler tries to use SSE registers there, which fails at the assembler > stage. > > Michael > > -- > printk("CPU[%d]: Sending penguins to jail...",smp_processor_id()); > 2.4.8 arch/sparc64/kernel/smp.c > |