diff options
Diffstat (limited to 'tools/lib/h5diff.c')
-rw-r--r-- | tools/lib/h5diff.c | 238 |
1 files changed, 119 insertions, 119 deletions
diff --git a/tools/lib/h5diff.c b/tools/lib/h5diff.c index 25e5f83..f0c6048 100644 --- a/tools/lib/h5diff.c +++ b/tools/lib/h5diff.c @@ -53,7 +53,7 @@ print_objname (diff_opt_t * options, hsize_t nfound) /*------------------------------------------------------------------------- * Function: do_print_objname * - * Purpose: print object name + * Purpose: print object name * *------------------------------------------------------------------------- */ @@ -195,7 +195,7 @@ hsize_t h5diff(const char *fname1, HDmemset(filenames, 0, 1024 * 2); - if(options->m_quiet && (options->m_verbose || options->m_report)) + if(options->m_quiet && (options->m_verbose || options->m_report)) { printf("Error: -q (quiet mode) cannot be added to verbose or report modes\n"); options->err_stat=1; @@ -208,10 +208,10 @@ hsize_t h5diff(const char *fname1, */ /* disable error reporting */ - H5E_BEGIN_TRY + H5E_BEGIN_TRY { /* open the files */ - if((file1_id = H5Fopen(fname1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + if((file1_id = H5Fopen(fname1, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { printf("h5diff: <%s>: unable to open file\n", fname1); options->err_stat = 1; @@ -223,7 +223,7 @@ hsize_t h5diff(const char *fname1, #endif goto out; } /* end if */ - if((file2_id = H5Fopen(fname2, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) + if((file2_id = H5Fopen(fname2, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { printf("h5diff: <%s>: unable to open file\n", fname2); options->err_stat = 1; @@ -264,7 +264,7 @@ hsize_t h5diff(const char *fname1, * object name was supplied *------------------------------------------------------------------------- */ - if( objname1 ) + if( objname1 ) { #ifdef H5_HAVE_PARALLEL if(g_Parallel) @@ -273,13 +273,13 @@ hsize_t h5diff(const char *fname1, #endif assert(objname2); options->cmn_objs = 1; /* eliminate warning */ - nfound = diff_compare(file1_id, - fname1, - objname1, + nfound = diff_compare(file1_id, + fname1, + objname1, info1, - file2_id, - fname2, - objname2, + file2_id, + fname2, + objname2, info2, options); } /* end if */ @@ -289,14 +289,14 @@ hsize_t h5diff(const char *fname1, *------------------------------------------------------------------------- */ - else + else { #ifdef H5_HAVE_PARALLEL - if(g_Parallel) + if(g_Parallel) { int i; - if((HDstrlen(fname1) > 1024) || (HDstrlen(fname2) > 1024)) + if((HDstrlen(fname1) > 1024) || (HDstrlen(fname2) > 1024)) { fprintf(stderr, "The parallel diff only supports path names up to 1024 characters\n"); MPI_Abort(MPI_COMM_WORLD, 0); @@ -311,10 +311,10 @@ hsize_t h5diff(const char *fname1, } /* end if */ #endif - nfound = diff_match(file1_id, - info1, - file2_id, - info2, + nfound = diff_match(file1_id, + info1, + file2_id, + info2, options); } /* end else */ @@ -323,7 +323,7 @@ hsize_t h5diff(const char *fname1, out: /* close */ - H5E_BEGIN_TRY + H5E_BEGIN_TRY { H5Fclose(file1_id); H5Fclose(file2_id); @@ -347,7 +347,7 @@ out: * * Date: May 9, 2003 * - * Modifications: + * Modifications: * * Jan 2005 Leon Arber, larber@uiuc.edu * Added support for parallel diffing @@ -355,7 +355,7 @@ out: * Aug 2008 Pedro Vicente, pvn@hdfgroup.org * Added a "contents" mode check. * If this mode is present, objects in both files must match (must be exactly the same) - * If this does not happen, the tool returns an error code of 1 + * If this does not happen, the tool returns an error code of 1 * (instead of the success code of 0) * *------------------------------------------------------------------------- @@ -381,7 +381,7 @@ hsize_t diff_match(hid_t file1_id, curr1 = 0; curr2 = 0; - while(curr1 < info1->nused && curr2 < info2->nused) + while(curr1 < info1->nused && curr2 < info2->nused) { /* criteria is string compare */ int cmp = HDstrcmp(info1->paths[curr1].path, info2->paths[curr2].path); @@ -394,14 +394,14 @@ hsize_t diff_match(hid_t file1_id, curr1++; curr2++; } /* end if */ - else if(cmp < 0) + else if(cmp < 0) { infile[0] = 1; infile[1] = 0; trav_table_addflags(infile, info1->paths[curr1].path, info1->paths[curr1].type, table); curr1++; } /* end else-if */ - else + else { infile[0] = 0; infile[1] = 1; @@ -413,7 +413,7 @@ hsize_t diff_match(hid_t file1_id, /* list1 did not end */ infile[0] = 1; infile[1] = 0; - while(curr1 < info1->nused) + while(curr1 < info1->nused) { trav_table_addflags(infile, info1->paths[curr1].path, info1->paths[curr1].type, table); curr1++; @@ -422,7 +422,7 @@ hsize_t diff_match(hid_t file1_id, /* list2 did not end */ infile[0] = 0; infile[1] = 1; - while(curr2 < info2->nused) + while(curr2 < info2->nused) { trav_table_addflags(infile, info2->paths[curr2].path, info2->paths[curr2].type, table); curr2++; @@ -432,7 +432,7 @@ hsize_t diff_match(hid_t file1_id, * print the list *------------------------------------------------------------------------- */ - if(options->m_verbose) + if(options->m_verbose) { printf("\n"); printf("file1 file2\n"); @@ -458,22 +458,22 @@ hsize_t diff_match(hid_t file1_id, { /* assume equal contents initially */ options->contents = 1; - + /* number of different objects */ if ( info1->nused != info2->nused ) { options->contents = 0; } - - - for( i = 0; i < table->nobjs; i++) + + + for( i = 0; i < table->nobjs; i++) { - if( table->objs[i].flags[0] != table->objs[i].flags[1] ) + if( table->objs[i].flags[0] != table->objs[i].flags[1] ) { options->contents = 0; } } - + } @@ -495,12 +495,12 @@ hsize_t diff_match(hid_t file1_id, HDmemset(workerTasks, 1, (g_nTasks - 1)); #endif - for(i = 0; i < table->nobjs; i++) + for(i = 0; i < table->nobjs; i++) { - if( table->objs[i].flags[0] && table->objs[i].flags[1]) + if( table->objs[i].flags[0] && table->objs[i].flags[1]) { options->cmn_objs = 1; - if(!g_Parallel) + if(!g_Parallel) { nfound += diff(file1_id, table->objs[i].name, @@ -508,7 +508,7 @@ hsize_t diff_match(hid_t file1_id, table->objs[i].name, options, table->objs[i].type); } /* end if */ #ifdef H5_HAVE_PARALLEL - else + else { int workerFound = 0; @@ -522,7 +522,7 @@ hsize_t diff_match(hid_t file1_id, */ /*Set up args to pass to worker task. */ - if(HDstrlen(table->objs[i].name) > 255) + if(HDstrlen(table->objs[i].name) > 255) { printf("The parallel diff only supports object names up to 255 characters\n"); MPI_Abort(MPI_COMM_WORLD, 0); @@ -534,7 +534,7 @@ hsize_t diff_match(hid_t file1_id, h5diffdebug2("busyTasks=%d\n", busyTasks); /* if there are any outstanding print requests, let's handle one. */ - if(busyTasks > 0) + if(busyTasks > 0) { int incomingMessage; @@ -542,7 +542,7 @@ hsize_t diff_match(hid_t file1_id, MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &incomingMessage, &Status); /* first block*/ - if(incomingMessage) + if(incomingMessage) { workerTasks[Status.MPI_SOURCE - 1] = 1; MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status); @@ -552,7 +552,7 @@ hsize_t diff_match(hid_t file1_id, } /* end if */ /* check to see if the print token was returned. */ - if(!havePrintToken) + if(!havePrintToken) { /* If we don't have the token, someone is probably sending us output */ print_incoming_data(); @@ -572,11 +572,11 @@ hsize_t diff_match(hid_t file1_id, } /* end if */ /* check to see if anyone needs the print token. */ - if(havePrintToken) + if(havePrintToken) { /* check incoming queue for print token requests */ MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &incomingMessage, &Status); - if(incomingMessage) + if(incomingMessage) { MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status); MPI_Send(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD); @@ -588,9 +588,9 @@ hsize_t diff_match(hid_t file1_id, /* check array of tasks to see which ones are free. * Manager task never does work, so freeTasks[0] is really * worker task 0. */ - for(n = 1; (n < g_nTasks) && !workerFound; n++) + for(n = 1; (n < g_nTasks) && !workerFound; n++) { - if(workerTasks[n-1]) + if(workerTasks[n-1]) { /* send file id's and names to first free worker */ MPI_Send(&args, sizeof(args), MPI_BYTE, n, MPI_TAG_ARGS, MPI_COMM_WORLD); @@ -605,7 +605,7 @@ hsize_t diff_match(hid_t file1_id, } /* end for */ h5diffdebug2("workerfound is %d \n", workerFound); - if(!workerFound) + if(!workerFound) { /* if they were all busy, we've got to wait for one free up * before we can move on. If we don't have the token, some @@ -613,15 +613,15 @@ hsize_t diff_match(hid_t file1_id, * return it. */ - if(!havePrintToken) + if(!havePrintToken) { - while(!havePrintToken) + while(!havePrintToken) { int incomingMessage; print_incoming_data(); MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status); - if(incomingMessage) + if(incomingMessage) { MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status); havePrintToken = 1; @@ -633,26 +633,26 @@ hsize_t diff_match(hid_t file1_id, } /* end while */ } /* end if */ /* if we do have the token, check for task to free up, or wait for a task to request it */ - else + else { /* But first print all the data in our incoming queue */ print_incoming_data(); MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &Status); - if(Status.MPI_TAG == MPI_TAG_DONE) + if(Status.MPI_TAG == MPI_TAG_DONE) { MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status); nfound += nFoundbyWorker.nfound; options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp; MPI_Send(&args, sizeof(args), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_ARGS, MPI_COMM_WORLD); } /* end if */ - else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST) + else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST) { int incomingMessage; MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status); MPI_Send(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD); - do + do { MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status); @@ -664,7 +664,7 @@ hsize_t diff_match(hid_t file1_id, options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp; MPI_Send(&args, sizeof(args), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_ARGS, MPI_COMM_WORLD); } /* end else-if */ - else + else { printf("ERROR: Invalid tag (%d) received \n", Status.MPI_TAG); MPI_Abort(MPI_COMM_WORLD, 0); @@ -679,20 +679,20 @@ hsize_t diff_match(hid_t file1_id, h5diffdebug("done with for loop\n"); #ifdef H5_HAVE_PARALLEL - if(g_Parallel) + if(g_Parallel) { /* make sure all tasks are done */ - while(busyTasks > 0) + while(busyTasks > 0) { MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &Status); - if(Status.MPI_TAG == MPI_TAG_DONE) + if(Status.MPI_TAG == MPI_TAG_DONE) { MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status); nfound += nFoundbyWorker.nfound; options->not_cmp = options->not_cmp | nFoundbyWorker.not_cmp; busyTasks--; } /* end if */ - else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN) + else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN) { MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_DONE, MPI_COMM_WORLD, &Status); nfound += nFoundbyWorker.nfound; @@ -700,10 +700,10 @@ hsize_t diff_match(hid_t file1_id, busyTasks--; havePrintToken = 1; } /* end else-if */ - else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST) + else if(Status.MPI_TAG == MPI_TAG_TOK_REQUEST) { MPI_Recv(NULL, 0, MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_REQUEST, MPI_COMM_WORLD, &Status); - if(havePrintToken) + if(havePrintToken) { int incomingMessage; @@ -721,12 +721,12 @@ hsize_t diff_match(hid_t file1_id, busyTasks--; } /* end if */ /* someone else must have it...wait for them to return it, then give it to the task that just asked for it. */ - else + else { int source = Status.MPI_SOURCE; int incomingMessage; - do + do { MPI_Iprobe(MPI_ANY_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &incomingMessage, &Status); @@ -741,7 +741,7 @@ hsize_t diff_match(hid_t file1_id, MPI_Send(NULL, 0, MPI_BYTE, source, MPI_TAG_PRINT_TOK, MPI_COMM_WORLD); } /* end else */ } /* end else-if */ - else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN) + else if(Status.MPI_TAG == MPI_TAG_TOK_RETURN) { MPI_Recv(&nFoundbyWorker, sizeof(nFoundbyWorker), MPI_BYTE, Status.MPI_SOURCE, MPI_TAG_TOK_RETURN, MPI_COMM_WORLD, &Status); nfound += nFoundbyWorker.nfound; @@ -758,7 +758,7 @@ hsize_t diff_match(hid_t file1_id, printf("%s", data); } /* end else-if */ - else + else { printf("ph5diff-manager: ERROR!! Invalid tag (%d) received \n", Status.MPI_TAG); MPI_Abort(MPI_COMM_WORLD, 0); @@ -811,10 +811,10 @@ hsize_t diff_compare(hid_t file1_id, int f1 = 0; int f2 = 0; hsize_t nfound = 0; - + ssize_t i = h5trav_getindex (info1, obj1_name); ssize_t j = h5trav_getindex (info2, obj2_name); - + if (i == -1) { parallel_print ("Object <%s> could not be found in <%s>\n", obj1_name, @@ -832,11 +832,11 @@ hsize_t diff_compare(hid_t file1_id, options->err_stat = 1; return 0; } - + /* use the name with "/" first, as obtained by iterator function */ obj1_name = info1->paths[i].path; obj2_name = info2->paths[j].path; - + /* objects are not the same type */ if (info1->paths[i].type != info2->paths[j].type) { @@ -847,14 +847,14 @@ hsize_t diff_compare(hid_t file1_id, options->not_cmp=1; return 0; } - - nfound = diff(file1_id, - obj1_name, - file2_id, - obj2_name, - options, + + nfound = diff(file1_id, + obj1_name, + file2_id, + obj2_name, + options, info1->paths[i].type); - + return nfound; } @@ -880,9 +880,9 @@ hsize_t diff_compare(hid_t file1_id, hsize_t diff(hid_t file1_id, const char *path1, - hid_t file2_id, - const char *path2, - diff_opt_t * options, + hid_t file2_id, + const char *path2, + diff_opt_t * options, h5trav_type_t type) { hid_t type1_id = (-1); @@ -891,8 +891,8 @@ hsize_t diff(hid_t file1_id, hid_t grp2_id = (-1); int ret; hsize_t nfound = 0; - - switch(type) + + switch(type) { /*------------------------------------------------------------------------- * H5TRAV_TYPE_DATASET @@ -903,7 +903,7 @@ hsize_t diff(hid_t file1_id, * verbose, always print name *------------------------------------------------------------------------- */ - if(options->m_verbose) + if(options->m_verbose) { if(print_objname(options, (hsize_t)1)) do_print_objname("dataset", path1, path2); @@ -916,9 +916,9 @@ hsize_t diff(hid_t file1_id, * disabling quiet mode *------------------------------------------------------------------------- */ - else + else { - if(options->m_quiet == 0) + if(options->m_quiet == 0) { /* shut up temporarily */ options->m_quiet = 1; @@ -926,7 +926,7 @@ hsize_t diff(hid_t file1_id, /* print again */ options->m_quiet = 0; - if(nfound) + if(nfound) { if(print_objname(options,nfound)) do_print_objname("dataset", path1, path2); @@ -939,7 +939,7 @@ hsize_t diff(hid_t file1_id, nfound = diff_dataset(file1_id, file2_id, path1, path2, options); } /* end else */ break; - + /*------------------------------------------------------------------------- * H5TRAV_TYPE_NAMED_DATATYPE *------------------------------------------------------------------------- @@ -949,20 +949,20 @@ hsize_t diff(hid_t file1_id, goto out; if((type2_id = H5Topen2(file2_id, path2, H5P_DEFAULT)) < 0) goto out; - + if((ret = H5Tequal(type1_id, type2_id)) < 0) goto out; - + /* if H5Tequal is > 0 then the datatypes refer to the same datatype */ nfound = (ret > 0) ? 0 : 1; - + if(print_objname(options,nfound)) do_print_objname("datatype", path1, path2); /* always print the number of differences found in verbose mode */ if(options->m_verbose) print_found(nfound); - + /*------------------------------------------------------------------------- * compare attributes * the if condition refers to cases when the dataset is a referenced object @@ -970,30 +970,30 @@ hsize_t diff(hid_t file1_id, */ if(path1) nfound += diff_attr(type1_id, type2_id, path1, path2, options); - + if(H5Tclose(type1_id) < 0) goto out; if(H5Tclose(type2_id) < 0) goto out; break; - + /*------------------------------------------------------------------------- * H5TRAV_TYPE_GROUP *------------------------------------------------------------------------- */ case H5TRAV_TYPE_GROUP: ret = HDstrcmp(path1, path2); - + /* if "path1" != "path2" then the groups are "different" */ nfound = (ret != 0) ? 1 : 0; - + if(print_objname(options, nfound)) do_print_objname("group", path1, path2); /* always print the number of differences found in verbose mode */ if(options->m_verbose) print_found(nfound); - + if((grp1_id = H5Gopen2(file1_id, path1, H5P_DEFAULT)) < 0) goto out; if((grp2_id = H5Gopen2(file2_id, path2, H5P_DEFAULT)) < 0) @@ -1006,14 +1006,14 @@ hsize_t diff(hid_t file1_id, */ if(path1) nfound += diff_attr(grp1_id, grp2_id, path1, path2, options); - + if(H5Gclose(grp1_id) < 0) goto out; if(H5Gclose(grp2_id) < 0) goto out; break; - - + + /*------------------------------------------------------------------------- * H5TRAV_TYPE_LINK *------------------------------------------------------------------------- @@ -1022,37 +1022,37 @@ hsize_t diff(hid_t file1_id, { H5L_info_t li1, li2; char *buf1, *buf2; - + if(H5Lget_info(file1_id, path1, &li1, H5P_DEFAULT) < 0) goto out; if(H5Lget_info(file1_id, path1, &li2, H5P_DEFAULT) < 0) goto out; - + buf1 = HDmalloc(li1.u.val_size); buf2 = HDmalloc(li2.u.val_size); - + if(H5Lget_val(file1_id, path1, buf1, li1.u.val_size, H5P_DEFAULT) < 0) goto out; if(H5Lget_val(file2_id, path2, buf2, li2.u.val_size, H5P_DEFAULT) < 0) goto out; - + ret = HDstrcmp(buf1, buf2); - + /* if "buf1" != "buf2" then the links are "different" */ nfound = (ret != 0) ? 1 : 0; - + if(print_objname(options, nfound)) do_print_objname("link", path1, path2); /* always print the number of differences found in verbose mode */ if(options->m_verbose) print_found(nfound); - + HDfree(buf1); HDfree(buf2); } break; - + /*------------------------------------------------------------------------- * H5TRAV_TYPE_UDLINK *------------------------------------------------------------------------- @@ -1060,19 +1060,19 @@ hsize_t diff(hid_t file1_id, case H5TRAV_TYPE_UDLINK: { H5L_info_t li1, li2; - + if(H5Lget_info(file1_id, path1, &li1, H5P_DEFAULT) < 0) goto out; if(H5Lget_info(file1_id, path1, &li2, H5P_DEFAULT) < 0) goto out; - + /* Only external links will have a query function registered */ if(li1.type == H5L_TYPE_EXTERNAL && li2.type == H5L_TYPE_EXTERNAL) { char *buf1, *buf2; buf1 = HDmalloc(li1.u.val_size); buf2 = HDmalloc(li2.u.val_size); - + if(H5Lget_val(file1_id, path1, buf1, li1.u.val_size, H5P_DEFAULT) < 0) { HDfree(buf1); HDfree(buf2); @@ -1083,7 +1083,7 @@ hsize_t diff(hid_t file1_id, HDfree(buf2); goto out; } /* end if */ - + /* If the buffers are the same size, compare them */ if(li1.u.val_size == li2.u.val_size) { if(H5Lget_val(file1_id, path1, buf1, li1.u.val_size, H5P_DEFAULT) < 0) { @@ -1100,20 +1100,20 @@ hsize_t diff(hid_t file1_id, } else ret = 1; - + /* if "buf1" != "buf2" then the links are "different" */ nfound = (ret != 0) ? 1 : 0; - + if(print_objname(options, nfound)) do_print_objname("external link", path1, path2); - + HDfree(buf1); HDfree(buf2); } /* end if */ else { /* If one or both of these links isn't an external link, we can only * compare information from H5Lget_info since we don't have a query - * function registered for them. + * function registered for them. * * If the link classes or the buffer length are not the * same, the links are "different" @@ -1122,17 +1122,17 @@ hsize_t diff(hid_t file1_id, nfound = 1; else nfound = 0; - + if (print_objname (options, nfound)) do_print_objname ("user defined link", path1, path2); } /* end else */ - + /* always print the number of differences found in verbose mode */ if(options->m_verbose) print_found(nfound); } break; - + default: if(options->m_verbose) printf("Comparison not supported: <%s> and <%s> are of type %s\n", @@ -1140,9 +1140,9 @@ hsize_t diff(hid_t file1_id, options->not_cmp = 1; break; } - + return nfound; - + out: options->err_stat = 1; |