/*
This is source of Leprechaun revision 13+++++, copyleft Sanmayce, 2010-Aug-27.

Comment/Uncomment accordingly in order to compile: 
#define _WIN32_ENVIRONMENT_
//#define _POSIX_ENVIRONMENT_

Linux compile(uncomment #include <io.h> line, ignore warnings):
gcc -D_FILE_OFFSET_BITS=64 -m32 -static -O3 -mtune=generic Leprechaun.c -o Leprechaun_r13+++++_generic_32bits.elf

Windows compile(uncomment #include <io.h> line, ignore warnings):
For Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 use:
cl /Ox /Wp64 /TcLeprechaun.c /FaLeprechaun

Windows compile(comment #include <io.h> line, ignore warnings):
For Intel(R) C++ Compiler Professional for applications running on IA-32, Version 11.1 use:
icl /Ox /Wp64 /TcLeprechaun.c /FaLeprechaun /w /QxHOST

Due to my ignorance(calderas in my C knowledge): 64bit code cannot be generated, for now.
Any improvement is welcome.
Enjoy!

Below is the gain in 13++ and 13+++:

Words per second performance: 5,974,513W/s
Word count: 4,582,451,898 of them 9,177,221 distinct
Number Of Trees(GREATER THE BETTER): 2855919
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 6321302

Words per second performance: 6,329,353W/s
Word count: 4,582,451,898 of them 9,177,221 distinct
Number Of Trees(GREATER THE BETTER): 2958681
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 6218540

The aftermath: 6,321,302 - 6,218,540 = 102,762 less collisions while the speed of hash is not slower for sure - I call this: double trouble avoidance.
Thanks to Fowler/Noll/Vo hash inventors.
*/

// To do: must learn how to align, at last.

/*
Enter-the-BESTer or an alchemical clash of pairs of primes.

When an x-bit hash where x < 16 and is not a power of 2 is needed,
here comes 'FNV1A_Hash_4_OCTETS': a slightly tuned FNV1A hash for a huge(22,202,980) wordlist of latin-letters-words.

Two improvements for the generic(base) FNV1A hash:
- first, better speed: by reducing 'imul' instructions when string is 4++ chars
- second, better dispersion: by experimenting(superficially-lite test done, so far) with 'FNV1_32_PRIME'

Or more concretely:
- For FNV1_32_INIT = 2166136261
- Giving to 'FNV1_32_PRIME' all primes between 2 and 11987
- Shifting by 16bits instead of 13bits, when 8192 slots are used

C code:
typedef unsigned char u_int8_t;
typedef unsigned long u_int32_t;

#define FNV1_32_INIT ((u_int32_t)2166136261)
#define FNV1_32_PRIME ((u_int32_t)1607)

#define FNV_32A_OP(hash, octet) \
    (((u_int32_t)(hash) ^ (u_int8_t)(octet)) * FNV1_32_PRIME)

#define FNV_32A_OP32(hash, octet) \
    (((u_int32_t)(hash) ^ (u_int32_t)(octet)) * FNV1_32_PRIME)

0800 // Invoking: FNV1A_Hash_4_OCTETS(wrd, wrdlen>>2) // = 0,1,2,3,4,5,6,7 [1..31]
0801 int FNV1A_Hash_4_OCTETS(char *str, int wrdlen_QUADRUPLETS)
0802 { 
0803 u_int32_t hash;
0804 char *p;
0805 
0806 hash = FNV1_32_INIT;
0807 p=str;
0808 
0809 // The goal of stage #1: to reduce number of 'imul's.
0810 
0811 // Stage #1:
0812 for (; wrdlen_QUADRUPLETS != 0; --wrdlen_QUADRUPLETS) {
0813     hash = FNV_32A_OP32(hash, (unsigned long)*(long *)p); // mov edi, DWORD PTR [eax]
0814     p=p+4; // add eax, 4
0815 }
0816 
0817 // Stage #2:
0818 for (; *p; ++p) {
0819     hash = FNV_32A_OP(hash, *p); // mov dl, BYTE PTR [eax]
0820 }
0821 
0822   //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
0823   return ((hash>>16) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
0824 }

Assembler code:
_FNV1A_Hash_4_OCTETS PROC NEAR
; Line 812
	mov	edx, DWORD PTR _wrdlen_QUADRUPLETS$[esp-4]
	test	edx, edx
	mov	eax, DWORD PTR _str$[esp-4]
	push	esi
	mov	esi, DWORD PTR _FNV1_32_PRIME
	mov	ecx, -2128831035
	je	SHORT $L1612
	push	edi
	npad	7
$L1610:
; Line 813
	mov	edi, DWORD PTR [eax]
	xor	edi, ecx
	imul	edi, esi
; Line 814
	add	eax, 4
	dec	edx
	mov	ecx, edi
	jne	SHORT $L1610
	pop	edi
$L1612:
; Line 818
	mov	dl, BYTE PTR [eax]
	test	dl, dl
	je	SHORT $L1619
$L1617:
; Line 819
	movzx	edx, dl
	xor	edx, ecx
	imul	edx, esi
	inc	eax
	mov	ecx, edx
	mov	dl, BYTE PTR [eax]
	test	dl, dl
	jne	SHORT $L1617
$L1619:
; Line 823
	mov	eax, ecx
	shr	eax, 16
	xor	eax, ecx
	and	eax, 8191
	pop	esi
; Line 824
	ret	0
_FNV1A_Hash_4_OCTETS ENDP


So, 'FNV1A_Hash_4_OCTETS' calculates faster and gives better distribution(3549448 for 1607), which is 0.6% better(less collisions), than generic 'FNV1A_Hash' with 3527916.

FNV proves to be great, dealing with 4x8bits(four octets) at once doesn't hurt distribution at all, I was amazed by consistency(stable behaviour) of 'FNV1A_Hash_4_OCTETS'.

I want to make a total clash of all possible pairs 'FNV1_32_INIT' & 'FNV1_32_PRIME' in order to lessen even a few thousand collisions. 
This is critical for speed performance e.g. when 30,974,750,142 words, the case of wikipedia-en-html.tar, must be hashed.
The current obstacle is needed-time: each filling (26 slots x 31 sub-slots x 8192 sub-sub-slots) executes in 32-36 seconds for each pair.
Such an easy task, but I can't see how to get done, it is not hard but slow even with 15 times faster testbed.

Between 1..1166136247 there are 58,834,113 primes (inclusive).
Between 1..16777619 there are 1,077,891 primes (inclusive).
Or 58834113*1077891 = 63,416,760,895,683 pairs or 2,010,932 years needed at one-pair-per-second rate.

Finding THE best pair in my opinion is a total alchemy, due to the very nature of hashing: which is mainly alchemical and partly scientific.
Since the magnum corpus of words is static-enough, THE pair is worthy to be found.

It doesn't take a think-tank to see the superiority of FNV, Fowler/Noll/Vo did reveal a thing of beauty.

Performance of 'FNV1A_Hash_4_OCTETS': 10236 words/clock or 105 MB/s|3,549,448 used slots (best)

CASE #1: with 'if (strlen(backup[j]) != 0)' before each execution
Performance of 'KuxHash3plus' aka '2in1': 8076 words/clock or 82 MB/s|3,410,463 used slots (worst)
Performance of 'FNV1A_Hash': 8079 words/clock or 83 MB/s|3,527,916 used slots
Performance of 'FNV1A_Hash_SHIFTless_XORless': 8109 words/clock or 83 MB/s|3,540,323 used slots

CASE #2: without 'if (strlen(backup[j]) != 0)' before each execution
Performance of 'KuxHash3plus' aka '2in1': 11673 words/clock or 119 MB/s|3,410,463 used slots (worst)
Performance of 'FNV1A_Hash': 11558 words/clock or 118 MB/s|3,527,916 used slots
Performance of 'FNV1A_Hash_SHIFTless_XORless': 11570 words/clock or 118 MB/s|3,540,323 used slots

Note: 
The 'strlen' overhead(CASE #1) is necessary due to priorly(before hash invocation) needed len-of-string for 'FNV1A_Hash_4_OCTETS'.
Almost always, that is the case, since parsing of incoming text must know length of words/lines/files.
In case of not knowing this length: ((119-105)/105)*100% = 13% degradation is unacceptable.
The 'strlen' is an awful brake.
Also whether the code overhead(one additional cycle) of 'FNV1A_Hash_4_OCTETS' is so successful(as a trade-off) or the testbed is deceiving I do not know, here I am not so sure regardless of notorious delays caused by 'imul' and 'div' instructions.
*/

/*
FNV1_32_PRIME: //?: 16777619

Above Binary-Search-Tree with MaxPEAK = 61 has NODEs = 61 and LEAFs = 1
Words per second performance: 1,046,822W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2775839

Above Binary-Search-Tree with MaxPEAK = 39 has NODEs = 72 and LEAFs = 15
Words per second performance: 1,356,588W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3539690

FNV1_32_PRIME: //3549448: 1607

Above Binary-Search-Tree with MaxPEAK = 61 has NODEs = 61 and LEAFs = 1
Words per second performance: 1,046,822W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2783970

Above Binary-Search-Tree with MaxPEAK = 38 has NODEs = 50 and LEAFs = 11
Words per second performance: 1,410,851W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3549395

FNV1_32_PRIME: //3550132: 175757909

Above Binary-Search-Tree with MaxPEAK = 60 has NODEs = 60 and LEAFs = 1
Words per second performance: 966,298W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2784479

Above Binary-Search-Tree with MaxPEAK = 39 has NODEs = 64 and LEAFs = 12
Words per second performance: 1,410,851W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3550115

FNV1_32_PRIME: //3550687: 201887489

Above Binary-Search-Tree with MaxPEAK = 60 has NODEs = 60 and LEAFs = 1
Words per second performance: 966,298W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2784377

Above Binary-Search-Tree with MaxPEAK = 40 has NODEs = 55 and LEAFs = 11
Words per second performance: 1,356,588W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3550528

FNV1_32_PRIME: //3550733: 172783361

Above Binary-Search-Tree with MaxPEAK = 59 has NODEs = 59 and LEAFs = 1
Words per second performance: 1,046,822W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2786362

Above Binary-Search-Tree with MaxPEAK = 38 has NODEs = 70 and LEAFs = 17
Words per second performance: 1,410,851W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3550746

FNV1_32_PRIME: //3550929: 204312319

Above Binary-Search-Tree with MaxPEAK = 61 has NODEs = 61 and LEAFs = 1
Words per second performance: 966,298W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2785581

Above Binary-Search-Tree with MaxPEAK = 37 has NODEs = 55 and LEAFs = 12
Words per second performance: 1,356,588W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3550886

Leprechaun_Microsoft.exe: FNV1_32_PRIME: //3551736: 107712257

Above Binary-Search-Tree with MaxPEAK = 61 has NODEs = 61 and LEAFs = 1
Words per second performance: 1,046,822W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2786515

Above Binary-Search-Tree with MaxPEAK = 36 has NODEs = 64 and LEAFs = 15
Words per second performance: 1,356,588W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3551744

Leprechaun_Intel.exe: FNV1_32_PRIME: //3551736: 107712257

Above Binary-Search-Tree with MaxPEAK = 61 has NODEs = 61 and LEAFs = 1
Words per second performance: 1,256,187W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_en-WORDS.lst
Size of all TEXTual Files: 146,973,879
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2786515

Above Binary-Search-Tree with MaxPEAK = 36 has NODEs = 64 and LEAFs = 15
Words per second performance: 1,603,240W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Size of all TEXTual Files: 415,982,896
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3551744

Wow: 1,603,240W/s vs 1,356,588W/s respectively Leprechaun_Intel.exe vs Leprechaun_Microsoft.exe, i.e. 18% betterment, no joke!
*/

// Windows: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  _CRTIMP size_t __cdecl fread(void *, size_t, size_t, FILE *);
//  _CRTIMP size_t __cdecl fwrite(const void *, size_t, size_t, FILE *);
//  _CRTIMP int __cdecl fgetpos(FILE *, fpos_t *);
//  _CRTIMP int __cdecl fsetpos(FILE *, const fpos_t *);

//  _CRTIMP __int64 __cdecl _lseeki64(int, __int64, int);
//  _CRTIMP __int64 __cdecl _telli64(int);
//  _CRTIMP __int64 __cdecl _filelengthi64(int);
//  above 3 are in 'io.h'

//  _CRTIMP int __cdecl fseek(FILE *, long, int);
//  _CRTIMP long __cdecl ftell(FILE *);
//  _CRTIMP int __cdecl fclose(FILE *);

//  #ifndef _SIZE_T_DEFINED
//  #ifdef  _WIN64
//  typedef unsigned __int64    size_t;
//  #else
//  typedef _W64 unsigned int   size_t;
//  #endif
//  #define _SIZE_T_DEFINED
//  #endif

//  typedef __int64 fpos_t;

// Linux: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  size_t fread (void *data, size_t size, size_t count, FILE *stream)
//  size_t fwrite (const void *data, size_t size, size_t count, FILE *stream)
//  int fgetpos (FILE *stream, fpos_t *position)
//  int fsetpos (FILE *stream, const fpos_t *position)

//  FILE * fopen64 (const char *filename, const char *opentype)
//  int fseeko64 (FILE *stream, off64_t offset, int whence)  
//  off64_t ftello64 (FILE *stream)  
//  int fclose (FILE *stream)  

//  off_t lseek (int filedes, off_t offset, int whence)
//  above 1 is in 'unistd.h'


// ============== MUST work both for Windows and Linux ==============
//#define _WIN32_ENVIRONMENT_
#define _POSIX_ENVIRONMENT_


#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif

// To do #1: Put this 31 in MAXwl: 'int MAXwl = 31;'
// To do #2: No need of flushing unsorted words to file: make backup[] array
//           instead of writing. And mostly sort 26 times!     
// HEAVY BUG in r.7: unsigned long Hill(unsigned long n)
//                   is NOT identical with
//                   unsigned long GRMBLhill[32]; // 00 not used, only 01..31
//                   BECAUSE DUMBEST DUMB Array GRMBLhill expects 'int' not
//                   'unsigned long' !!!

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#if defined(_WIN32_ENVIRONMENT_)
#include <io.h> // needed for Windows' 'lseeki64' and 'telli64'
//Above line must be commented in order to compile with Intel C compiler: an error "can't find io.h" occurs.
#else
#endif /* defined(_WIN32_ENVIRONMENT_)  */

typedef unsigned char char_t;
typedef char_t *string;

	clock_t clocks1, clocks2;
	int Bozan;

typedef unsigned char u_int8_t; //FNV only
typedef unsigned long u_int32_t; //FNV only
typedef unsigned long long u_int64_t; //FNV only

// SINHA fragment[

#define swapKAZE(a, b) { t = *(a); *(a) = *(b); *(b) = t; }

static void InsertSortKAZE(string *a, int n, int d) //void inssort(unsigned char **a, int n, int d)
{   string *pi, *pj, s, t;                          //unsigned char **pi, **pj, *s, *t;
    for (pi = a + 1; --n > 0; pi++)
        for (pj = pi; pj > a; pj--) {
            /* Inline strcmp: break if *(pj-1) <= *pj */
            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
                ;
            if (*s <= *t)
                break;
            swapKAZE(pj, pj-1);
    }
}

//int cmpit(unsigned char **h1, unsigned char **h2)
//{
//    return( scmp(*h1, *h2) );
//}

//int scmp( unsigned char *s1, unsigned char *s2 )
//{
//    while( *s1 != '\0' && *s1 == *s2 )
//    {
//        s1++;
//        s2++;
//    }
//    return( *s1-*s2 );
//}

//static void simplesort(string a[], int n, int b)
//{
//   int i, j;
//   string tmp;
//
//   for (i = 1; i < n; i++)
//      for (j = i; j > 0 && scmp(a[j-1]+b, a[j]+b) > 0; j--)
//         { tmp = a[j]; a[j] = a[j-1]; a[j-1] = tmp; }
//}

// SINHA fragment]

// mkqsort.c BEGIN **********************************************************
/*
   Multikey quicksort, a radix sort algorithm for arrays of character
   strings by Bentley and Sedgewick.

   J. Bentley and R. Sedgewick. Fast algorithms for sorting and
   searching strings. In Proceedings of 8th Annual ACM-SIAM Symposium
   on Discrete Algorithms, 1997.

   http://www.CS.Princeton.EDU/~rs/strings/index.html

   The code presented in this file has been tested with care but is
   not guaranteed for any purpose. The writer does not offer any
   warranties nor does he accept any liabilities with respect to
   the code.

   Ranjan Sinha, 1 jan 2003.

   School of Computer Science and Information Technology,
   RMIT University, Melbourne, Australia
   rsinha@cs.rmit.edu.au

*/

//#include "sortstring.h"

/* MULTIKEY QUICKSORT */

#ifndef min
#define min(a, b) ((a)<=(b) ? (a) : (b))
#endif


// ------------------------------- BTREE [
#define false -1
#define true 0

struct nodeBTREE {
int data;
struct nodeBTREE* left;
struct nodeBTREE* right;
};

// ------------------------------- BTREE ]


/* ssort2 -- Faster Version of Multikey Quicksort */

void vecswap2(unsigned char **a, unsigned char **b, int n)
{   while (n-- > 0) {
        unsigned char *t = *a;
        *a++ = *b;
        *b++ = t;
    }
}

#define swap2(a, b) { t = *(a); *(a) = *(b); *(b) = t; }
#define ptr2char(i) (*(*(i) + depth))

unsigned char **med3func(unsigned char **a, unsigned char **b, unsigned char **c, int depth)
{   int va, vb, vc;
    if ((va=ptr2char(a)) == (vb=ptr2char(b)))
        return a;
    if ((vc=ptr2char(c)) == va || vc == vb)
        return c;       
    return va < vb ?
          (vb < vc ? b : (va < vc ? c : a ) )
        : (vb > vc ? b : (va < vc ? a : c ) );
}
#define med3(a, b, c) med3func(a, b, c, depth)

void inssort(unsigned char **a, int n, int d)
{   unsigned char **pi, **pj, *s, *t;
    for (pi = a + 1; --n > 0; pi++)
        for (pj = pi; pj > a; pj--) {
            /* Inline strcmp: break if *(pj-1) <= *pj */
            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
                ;
            if (*s <= *t)
                break;
            swap2(pj, pj-1);
    }
}

void mkqsort(unsigned char **a, int n, int depth)
{   int d, r, partval;
    unsigned char **pa, **pb, **pc, **pd, **pl, **pm, **pn, *t;
    if (n < 20) {
        inssort(a, n, depth);
        return;
    }
    pl = a;
    pm = a + (n/2);
    pn = a + (n-1);
    if (n > 30) { /* On big arrays, pseudomedian of 9 */
        d = (n/8);
        pl = med3(pl, pl+d, pl+2*d);
        pm = med3(pm-d, pm, pm+d);
        pn = med3(pn-2*d, pn-d, pn);
    }
    pm = med3(pl, pm, pn);
    swap2(a, pm);
    partval = ptr2char(a);
    pa = pb = a + 1;
    pc = pd = a + n-1;
    for (;;) {
        while (pb <= pc && (r = ptr2char(pb)-partval) <= 0) {
            if (r == 0) { swap2(pa, pb); pa++; }
            pb++;
        }
        while (pb <= pc && (r = ptr2char(pc)-partval) >= 0) {
            if (r == 0) { swap2(pc, pd); pd--; }
            pc--;
       }
        if (pb > pc) break;
        swap2(pb, pc);
        pb++;
        pc--;
    }
    pn = a + n;
    r = min(pa-a, pb-pa);    vecswap2(a,  pb-r, r);
    r = min(pd-pc, pn-pd-1); vecswap2(pb, pn-r, r);
    if ((r = pb-pa) > 1)
        mkqsort(a, r, depth);
    if (ptr2char(a + r) != 0)
        mkqsort(a + r, pa-a + pn-pd-1, depth+1);
    if ((r = pd-pc) > 1)
        mkqsort(a + n-r, r, depth);
}

void mkqsort_main(unsigned char **a, int n) { mkqsort(a, n, 0); }
// mkqsort.c END ************************************************************

// Why Sinha uses int instead of long??!!
static int readlines(char *file_name, string **lines)
{
   int nlines = 0;
   size_t size;
   FILE *in_file;
   string basep, cur, next;
   string *ASbackup;

   if (!(in_file = fopen(file_name, "rb"))) {
      printf( "Leprechaun: Can't open file %s \n", file_name ); 
      exit(-1);
   }
   fseek(in_file, 0, SEEK_END);
   size = ftell(in_file);
   fseek(in_file, 0, SEEK_SET);
   if (!(basep = (string) malloc(size*sizeof(char_t)))) return -1;
   printf( "Allocated memory for words in MB: %lu\n", ((size*sizeof(char_t))>>20)+1 );
   if (fread(basep, 1, size, in_file) < size) {
      printf( "Leprechaun: Can't read file %s \n", file_name ); 
      exit(-1);
   }
   fclose(in_file);

// GET nlines:
   cur = basep;
   while (cur < basep + size) {
      next = cur;
      while ((next < basep + size) && (*next != '\n')) {next++;}
      *--next = '\0';          // This is ala DOS i.e. Windows
                               // 1310 not 10(\n=10)
      cur = next + 2;
      nlines++;
   }

// printf("%lu\n",(unsigned long)*lines); -> backup = *lines = 0
ASbackup = (string *)malloc( nlines*sizeof(string) ); // sizeof(string) is 4
if( ASbackup == NULL )
{ puts( "Leprechaun: Needed memory allocation denied!\n" ); return( 1 ); }
printf( "Allocated memory for pointers-to-words in MB: %lu\n", ((nlines*sizeof(string))>>20)+1 );
*lines = ASbackup;
//printf("%lu\n",(unsigned long)*lines); -> backup = *lines = ASbackup = 6946888

// Upload nlines times:
   nlines = 0;
   cur = basep;
   while (cur < basep + size) {
      next = cur;
      while ((next < basep + size) && (*next != '\n')) {next++;}
      *--next = '\0';          // This is ala DOS i.e. Windows
                               // 1310 not 10(\n=10)
      ASbackup[nlines] = cur;
      cur = next + 2;
      nlines++;
   }
   return nlines;
}

void x64toaKAZE (      /* stdcall is faster and smaller... Might as well use it for the helper. */
        unsigned long long val,
        char *buf,
        unsigned radix,
        int is_neg
        )
{
        char *p;                /* pointer to traverse string */
        char *firstdig;         /* pointer to first digit */
        char temp;              /* temp char */
        unsigned digval;        /* value of digit */

        p = buf;

        if ( is_neg )
        {
            *p++ = '-';         /* negative, so output '-' and negate */
            val = (unsigned long long)(-(long long)val);
        }

        firstdig = p;           /* save pointer to first digit */

        do {
            digval = (unsigned) (val % radix);
            val /= radix;       /* get next digit */

            /* convert to ascii and store */
            if (digval > 9)
                *p++ = (char) (digval - 10 + 'a');  /* a letter */
            else
                *p++ = (char) (digval + '0');       /* a digit */
        } while (val > 0);

        /* We now have the digit of the number in the buffer, but in reverse
           order.  Thus we reverse them now. */

        *p-- = '\0';            /* terminate string; p points to last digit */

        do {
            temp = *p;
            *p = *firstdig;
            *firstdig = temp;   /* swap *p and *firstdig */
            --p;
            ++firstdig;         /* advance to next two digits */
        } while (firstdig < p); /* repeat until halfway */
}

/* Actual functions just call conversion helper with neg flag set correctly,
   and return pointer to buffer. */

char * _i64toaKAZE (
        long long val,
        char *buf,
        int radix
        )
{
        x64toaKAZE((unsigned long long)val, buf, radix, (radix == 10 && val < 0));
        return buf;
}

char * _ui64toaKAZE (
        unsigned long long val,
        char *buf,
        int radix
        )
{
        x64toaKAZE(val, buf, radix, 0);
        return buf;
}

char * _ui64toaKAZEzerocomma (
        unsigned long long val,
        char *buf,
        int radix
        )
{
                        char *p;
                        char temp;
                        int txpman;
                        int pxnman;
        x64toaKAZE(val, buf, radix, 0);
                        p = buf;
                        do {
                        } while (*++p != '\0');
                        p--; // p points to last digit
                             // buf points to first digit
                        buf[26] = 0;
                        txpman = 1;
                        pxnman = 0;
                        do
                        { if (buf <= p)
                          { temp = *p;
                            buf[26-txpman] = temp; pxnman++;
                            p--;
                            if (pxnman % 3 == 0)
                            { txpman++;
                              buf[26-txpman] = (char) (',');
                            }
                          }
                          else
                          { buf[26-txpman] = (char) ('0'); pxnman++;
                            if (pxnman % 3 == 0)
                            { txpman++;
                              buf[26-txpman] = (char) (',');
                            }
                          }
                          txpman++;
                        } while (txpman <= 26);
        return buf;
}

char * _ui64toaKAZEcomma (
        unsigned long long val,
        char *buf,
        int radix
        )
{
                        char *p;
                        char temp;
                        int txpman;
                        int pxnman;
        x64toaKAZE(val, buf, radix, 0);
                        p = buf;
                        do {
                        } while (*++p != '\0');
                        p--; // p points to last digit
                             // buf points to first digit
                        buf[26] = 0;
                        txpman = 1;
                        pxnman = 0;
                        while (buf <= p)
                        { temp = *p;
                          buf[26-txpman] = temp; pxnman++;
                          p--;
                          if (pxnman % 3 == 0 && buf <= p)
                          { txpman++;
                            buf[26-txpman] = (char) (',');
                          }
                          txpman++;
                        } 
        return buf+26-(txpman-1);
}

unsigned char KuxHash(char *str)
{ unsigned char h = 0;
  int max31 = 0;
  //while (*str)
  while (str[max31])
  { h = h ^ str[max31++];
    //h = h ^ *str++; // I am not sure 'str' is returned changed after return?!
  }
  return h; // 00..255 i.e. 2^8=256
}

int KuxHash2(char *str) 
{ int h = 0;
  unsigned long h2 = 0; // must be long: 31*'z'=31*122
  int max31 = 0;
  while (str[max31])
  { h = h ^ str[max31]; // 00..255 i.e. 2^8=256
    //h2 = h2 + str[max31++];       // [113s]
    h2 = h2 + max31 * str[max31++];
  }
  h=h<<4; // 00..15 i.e. 2^4=16
  //h = h|( str[0] ^ str[max31-1] ); // [111s] a..z: each XOR each gives 00..31
  h = h|( h2%((1<<4)-1) );
  return h; // 00..4095 i.e. 2^12=4096
}

//OSHO test - Attempts to Find/Put a WORD into linked list count: 32,011,937
int KuxHash3(char *str) 
{ int h = 0;
  unsigned long h2 = 0; // must be long: 31*'z'=31*122
  int max31 = 0;
  while (str[max31])
  { h = h ^ str[max31]; // 00..255 i.e. 2^8=256
    //h2 = h2 + str[max31++];       // [113s]
    h2 = h2 + str[max31++] * (max31+1);
  }
// Result is: 7bits in 'h' and 32bits in 'h2'.

                        //printf("%s:\n ",str);
                        //printf("%d ",h);
  h=h<<6; // 00..15 i.e. 00-05+7bits=13bits
                        //printf("%d ",h);
                        //printf("%d ",h2);
  //h = h|( str[0] ^ str[max31-1] ); // [111s] a..z: each XOR each gives 00..31
  h = h|( h2%((1<<6)-1) ); // 64-1=63=9*7; 61 is prime
                        //printf("%d \n",h);
  return h; // 00..8191 i.e. 2^13=8192
}

//OSHO test - Attempts to Find/Put a WORD into a linked list count: 31,927,285
int KuxHash3plus(char *str)
{ int h = 0;
  unsigned long h2 = 0; // must be long: 31*'z'=31*122
  int max31 = 0;
  while (str[max31])
  { h = h ^ str[max31]; // 00..255 i.e. 2^8=256
    //h2 = h2 + str[max31++];       // [113s]
    h2 = h2 + str[max31++] * (max31+1);
  }
// Result is: 7bits in 'h' and 32bits in 'h2'.

                        //printf("%s:\n ",str);
                        //printf("%d ",h);
// a in ASCII is 097 = 0110 0001
// z in ASCII is 122 = 0111 1010
// Above two lines show that bits 8-7-6 are always 0-1-1 so need for low 5 bits.
  //h=h<<8; // 00..15 i.e. 5bits + 00-07bits=13bits
                        //printf("%d ",h);
                        //printf("%d ",h2);
  //h = h|( str[0] ^ str[max31-1] ); // [111s] a..z: each XOR each gives 00..31
  h = (( h<<8 )|( h2%(251) ))&8191; // 251 prime
                        //printf("%d \n",h);
  return h; // 00..8191 i.e. 2^13=8192
}

/*
PUBLIC	_KuxHash3plus
; Function compile flags: /Ogty
_TEXT	SEGMENT
_str$ = 8						; size = 4
_KuxHash3plus PROC NEAR
; Line 511
	mov	ecx, DWORD PTR _str$[esp-4]
	mov	dl, BYTE PTR [ecx]
	push	esi
	xor	esi, esi
	xor	eax, eax
	test	dl, dl
	je	SHORT $L1561
	push	ebx
	push	edi
	mov	edi, 1
	sub	edi, ecx
	npad	8
$L1560:
; Line 512
	movsx	edx, BYTE PTR [ecx]
; Line 514
	lea	ebx, DWORD PTR [edi+ecx]
	imul	ebx, edx
	xor	esi, edx
	mov	dl, BYTE PTR [ecx+1]
	add	eax, ebx
	inc	ecx
	test	dl, dl
	jne	SHORT $L1560
	pop	edi
	pop	ebx
$L1561:
; Line 527
	xor	edx, edx
	mov	ecx, 251				; 000000fbH
	div	ecx
	shl	esi, 8
	mov	eax, edx
; Line 529
	or	eax, esi
	and	eax, 8191				; 00001fffH
	pop	esi
; Line 530
	ret	0
_KuxHash3plus ENDP
_TEXT	ENDS
*/

//OSHO test - Attempts to Find/Put a WORD into a linked list count: 32,021,975
int KuxHash4(char *str)
{ 
  int h2 = 0; 
    for (; *str != 0; str++) {
      //h2 = (127*h2 + *str) % (8192-1); // 2^13-1 = 8191 is Mersenne prime
      h2 = ((h2<<7) + *str) % (8192-1); // 2^13-1 = 8191 is Mersenne prime
    }

  return h2; // 00..8191 i.e. 2^13=8192
}

/*
int hash(char *v, int M)
  { int h = 0, a = 127;
    for (; *v != 0; v++) 
      h = (a*h + *v) % M;
    return h;
  }

int hashU(char *v, int M)
  { int h, a = 31415, b = 27183;
    for (h = 0; *v != 0; v++, a = a*b % (M-1)) 
        h = (a*h + *v) % M;
    return (h < 0) ? (h + M) : h;
  }
*/

// Kaze: My appreciation of FNV is far beyound C code optimization, it is alchemical, and why not, magical.

/*
FNV hash history
    The basis of the FNV hash algorithm was taken from an idea sent as reviewer comments to the IEEE POSIX P1003.2 committee 
by Glenn Fowler and Phong Vo back in 1991. In a subsequent ballot round: Landon Curt Noll improved on their algorithm. 
Some people tried this hash and found that it worked rather well. In an EMail message to Landon, they named it 
the ``Fowler/Noll/Vo'' or FNV hash.
    FNV hashes are designed to be fast while maintaining a low collision rate. The FNV speed allows one to quickly hash 
lots of data while maintaining a reasonable collision rate. The high dispersion of the FNV hashes makes them well suited 
for hashing nearly identical strings such as URLs, hostnames, filenames, text, IP addresses, etc. 
*/

/* NOTE: u_int64_t is a 64 bit unsigned type */
/* NOTE: u_int32_t is a 32 bit unsigned type */
/* NOTE: u_int16_t is a 16 bit unsigned type */
/* NOTE: u_int8_t is a 8 bit unsigned type */

//typedef unsigned char u_int8_t; //FNV only
//typedef unsigned long u_int32_t; //FNV only
//typedef unsigned long long u_int64_t; //FNV only

// 32 bit FNV_prime = 2^24 + 2^8 + 0x93 = 16777619
// 64 bit FNV_prime = 2^40 + 2^8 + 0xb3 = 1099511628211

// 32 bit offset_basis = 2166136261
// 64 bit offset_basis = 14695981039346656037

#define FNV1_64_INIT ((u_int64_t)14695981039346656037)
#define FNV1_64_PRIME ((u_int64_t)1099511628211)
#define FNV1_32_INIT ((u_int32_t)2166136261)
#define FNV1_32_PRIME ((u_int32_t)107712257)
// FNV1A_Hash_4_OCTETS gives dispersion as follows:
//3549448: 1607
//3549669: 171072511
//3549702: 124041217
//3549787: 121802497
//3549866: 175430911
//3549939: 180818431
//3549981: 118699519
//3550132: 175757909
//3550687: 201887489
//3550733: 172783361
//3550929: 204312319
//3551736: 107712257

#define FNV_64A_OP(hash, octet) \
    (((u_int64_t)(hash) ^ (u_int8_t)(octet)) * FNV1_64_PRIME)

#define FNV_64A_OP64(hash, octet) \
    (((u_int64_t)(hash) ^ (u_int64_t)(octet)) * FNV1_64_PRIME)

#define FNV_32A_OP_GENERIC(hash, octet) \
    (((u_int32_t)(hash) ^ (u_int8_t)(octet)) * 16777619)

#define FNV_32A_OP(hash, octet) \
    (((u_int32_t)(hash) ^ (u_int8_t)(octet)) * FNV1_32_PRIME)

#define FNV_32A_OP_MULless_core(hash, octet) \
    ( (u_int32_t)(hash) ^ (u_int8_t)(octet) )

#define FNV_32A_OP_MULless(hash, octet) \
    ( (FNV_32A_OP_MULless_core(hash, octet)<<5) - FNV_32A_OP_MULless_core(hash, octet) )

#define FNV_32A_OP32(hash, octet) \
    (((u_int32_t)(hash) ^ (u_int32_t)(octet)) * FNV1_32_PRIME)

#define FNV_32A_OP64(hash, octet) \
    (((u_int64_t)(hash) ^ (u_int64_t)(octet)) * FNV1_32_PRIME)

#define FNV_32A_OP32_MULless_core(hash, octet) \
    ( (u_int32_t)(hash) ^ (u_int32_t)(octet) )

#define FNV_32A_OP32_MULless(hash, octet) \
    ( (FNV_32A_OP32_MULless_core(hash, octet)<<5) - FNV_32A_OP32_MULless_core(hash, octet) )


// Invoking: FNV1A_Hash_4_OCTETS_31(wrd, wrdlen>>2) // = 0,1,2,3,4,5,6,7 [1..31]
int FNV1A_Hash_4_OCTETS_31(char *str, int wrdlen_QUADRUPLETS)
{ 
u_int32_t hash;
char *p;

hash = FNV1_32_INIT;
p=str;

// The goal of stage #1: to reduce number of 'imul's in fact to reduce loops.

// Stage #1:
for (; wrdlen_QUADRUPLETS != 0; --wrdlen_QUADRUPLETS) {
    hash = FNV_32A_OP32_MULless(hash, (unsigned long)*(long *)p); // mov edi, DWORD PTR [eax]
    p=p+4; // add eax, 4
}

// Stage #2:
for (; *p; ++p) {
    hash = FNV_32A_OP_MULless(hash, *p); // mov dl, BYTE PTR [ecx]
}

  //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
  return ((hash>>16) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
}


// Invoking: FNV1A_Hash_4_OCTETS(wrd, wrdlen>>2) // = 0,1,2,3,4,5,6,7 [1..31]
int FNV1A_Hash_4_OCTETS(char *str, int wrdlen_QUADRUPLETS)
{ 
u_int32_t hash;
char *p;

hash = FNV1_32_INIT;
p=str;

// The goal of stage #1: to reduce number of 'imul's.

// Stage #1:
for (; wrdlen_QUADRUPLETS != 0; --wrdlen_QUADRUPLETS) {
    hash = FNV_32A_OP32(hash, (unsigned long)*(long *)p); // mov edi, DWORD PTR [eax]
    p=p+4; // add eax, 4
}

// Stage #2:
for (; *p; ++p) {
    hash = FNV_32A_OP(hash, *p); // mov dl, BYTE PTR [ecx]
}

  //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
  return ((hash>>16) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
}


// Invoking: FNV1A_Hash_8_OCTETS(wrd, wrdlen>>3) // = 0,1,2,3 [1..31]
int FNV1A_Hash_8_OCTETS(char *str, int wrdlen_OCTETS)
{ 
u_int32_t hash;
char *p;

hash = FNV1_32_INIT;
p=str;

// The goal of stage #1: to reduce number of 'imul's.

// Stage #1:
for (; wrdlen_OCTETS != 0; --wrdlen_OCTETS) {
    hash = FNV_32A_OP64(hash, (unsigned long long)*(long *)p); // mov edi, DWORD PTR [eax]
    p=p+8; // add eax, 4
}

// Stage #2:
for (; *p; ++p) {
    hash = FNV_32A_OP(hash, *p); // mov dl, BYTE PTR [ecx]
}

  //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
  return ((hash>>16) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
}


// Invoking: FNV1A_Hash_Granularity(wrd, wrdlen>>0|2|3, 0|2|3) 
int FNV1A_Hash_Granularity(char *str, int wrdlen_granulated, int Granularity) // wrdlen>>0=wrdlen
{ 
u_int32_t hash;
u_int64_t hash64;
char *p;

hash = FNV1_32_INIT;
p=str;

// The goal of stage #1: to reduce number of 'imul's and mainly: the number of loops.

// Stage #1:
        if (Granularity == 2) {
for (; wrdlen_granulated != 0; --wrdlen_granulated) {
    hash = FNV_32A_OP32(hash, (u_int32_t)*(u_int32_t *)p);
    p=p+4; // (1<<Granularity): 1<<0=1, 1<<2=4, 1<<3=8
}
        }
        if (Granularity == 3) {
hash64 = FNV1_64_INIT;
for (; wrdlen_granulated != 0; --wrdlen_granulated) {
    hash64 = FNV_64A_OP64(hash64, (u_int64_t)*(u_int64_t *)p);
    p=p+8; // (1<<Granularity): 1<<0=1, 1<<2=4, 1<<3=8
}
for (; *p; ++p) {
    hash64 = FNV_64A_OP(hash64, (u_int8_t)*(u_int8_t *)p);
}

  //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
  return ((hash64>>51) ^ hash64) & 8191; // 00..8191 i.e. 2^13=8192
  // probably better shifting is not by 16 bits but ...
  //hash64>>16: 3,544,160 just bad
  //hash64>>33: 3,547,854
  //hash64>>34: 3,547,266
  //hash64>>35: 3,547,453
  //hash64>>36: 3,547,242
  //hash64>>40: 3,548,263
  //hash64>>44: 3,548,242
  //hash64>>45: 3,549,056
  //hash64>>46: 3,549,207
  //hash64>>47: 3,549,094
  //hash64>>50: 3,549,392
  //hash64>>51: 3,549,395 i.e. maximum shift: the 13 most significant bits i.e. (64-13); closest to 3,549,448

// Above results are obtained for following set: 
//if (wrdlen<=19) // 4x4+3=19 i.e. last contains 7 clashes
//              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>2, 2)<<2; //13+++++
//else            // 2x8+4=20 i.e. first contains 6 clashes
//              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>3, 3)<<2; //13+++++
        }

        //if (Granularity != 3) {
// Stage #2:
for (; *p; ++p) {
    hash = FNV_32A_OP(hash, (u_int8_t)*(u_int8_t *)p);
}

  //return ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13
  return ((hash>>16) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
        //}
}


// char *string;		/* the string to 64 bit FNV-1a hash */
// u_int64_t hash;		/* will hold the final value of the hash */
// char *p;
// 
// hash = FNV1_64_INIT;
// for (p=string; *p; ++p) {
//     hash = FNV_64A_OP(hash, *p);
// }


// If you need an x-bit hash where x is not a power of 2, 
// then we recommend that you compute the FNV hash that is just larger than x-bits and xor-fold the result down to x-bits.
// By xor-folding we mean shift the excess high order bits down and xor them with the lower x-bits. 
// For tiny x < 16 bit values, we recommend using a 32 bit FNV-1 hash as follows:

//    /* NOTE: for 0 < x < 16 ONLY!!! */
//    #define TINY_MASK(x) (((u_int32_t)1<<(x))-1)
//    #define FNV1_32_INIT ((u_int32_t)2166136261)
//    u_int32_t hash;
//    void *data;
//    size_t data_len;
//
//    hash = fnv_32_buf(data, data_len, FNV1_32_INIT);
//    hash = (((hash>>x) ^ hash) & TINY_MASK(x));


int FNV1A_Hash_SHIFTless_XORless(char *str)
{ 
u_int32_t hash;		/* will hold the final value of the hash */
char *p;

hash = FNV1_32_INIT;
for (p=str; *p; ++p) {
    hash = FNV_32A_OP(hash, *p);
}
//hash = ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13

  return hash & 8191; // 00..8191 i.e. 2^13=8192
}

/*
_FNV1A_Hash_SHIFTless_XORless PROC NEAR
; Line 721
	mov	edx, DWORD PTR _str$[esp-4]
	mov	cl, BYTE PTR [edx]
	test	cl, cl
	mov	eax, -2128831035			; 811c9dc5H
	je	SHORT $L1582
	npad	1
$L1580:
; Line 722
	movzx	ecx, cl
	xor	ecx, eax
	imul	ecx, 16777619				; 01000193H
	inc	edx
	mov	eax, ecx
	mov	cl, BYTE PTR [edx]
	test	cl, cl
	jne	SHORT $L1580
$L1582:
; Line 726
	and	eax, 8191				; 00001fffH
; Line 727
	ret	0
_FNV1A_Hash_SHIFTless_XORless ENDP
*/


int FNV1A_Hash(char *str)
{ 
u_int32_t hash;		/* will hold the final value of the hash */
char *p;

hash = FNV1_32_INIT;
for (p=str; *p; ++p) {
    hash = FNV_32A_OP(hash, *p);
}
//hash = ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13

  return ((hash>>13) ^ hash) & 8191; // 00..8191 i.e. 2^13=8192
}

/*
_FNV1A_Hash PROC NEAR
; Line 722
	mov	edx, DWORD PTR _str$[esp-4]
	mov	al, BYTE PTR [edx]
	test	al, al
	mov	ecx, -2128831035			; 811c9dc5H
	je	SHORT $L1582
	npad	1
$L1580:
; Line 723
	movzx	eax, al
	xor	eax, ecx
	imul	eax, 16777619				; 01000193H
	inc	edx
	mov	ecx, eax
	mov	al, BYTE PTR [edx]
	test	al, al
	jne	SHORT $L1580
$L1582:
; Line 727
	mov	eax, ecx
	shr	eax, 13					; 0000000dH
	xor	eax, ecx
	and	eax, 8191				; 00001fffH
; Line 728
	ret	0
_FNV1A_Hash ENDP
*/

/*
Wayne Diamond implemented 32-bit FNV algorithm in PowerBASIC inline x86 assembly:


    FUNCTION FNV32(BYVAL dwOffset AS DWORD, BYVAL dwLen AS DWORD, BYVAL offset_basis AS DWORD) AS DWORD
    #REGISTER NONE
    ! mov esi, dwOffset      ;esi = ptr to buffer
    ! mov ecx, dwLen         ;ecx = length of buffer (counter)
    ! mov eax, offset_basis  ;set to 2166136261 for FNV-1
    ! mov edi, &h01000193    ;FNV_32_PRIME = 16777619
    ! xor ebx, ebx           ;ebx = 0
    nextbyte:
    ! mul edi                ;eax = eax * FNV_32_PRIME
    ! mov bl, [esi]          ;bl = byte from esi
    ! xor eax, ebx           ;al = al xor bl
    ! inc esi                ;esi = esi + 1 (buffer pos)
    ! dec ecx                ;ecx = ecx - 1 (counter)
    ! jnz nextbyte           ;if ecx is 0, jmp to NextByte
    ! mov FUNCTION, eax      ;else, function = eax
    END FUNCTION

Wayne said:

    ''Just thought I should let you know that I've ported the 32-bit FNV algorithm over to inline assembly. 
It's actually in PowerBASIC (www.powerbasic.com) format - a compiler I use, but the main function is all assembly. 
It could be optimized further in terms of saving a couple of clock cycles, 
but it's fairly optimized al ready - only 6 instructions in the main loop, plus 5 setup instructions, 
and compiles to just 33 bytes.'' 

M.S.Schulte sent us these 32-bit FNV-1 and FNV-1a x86 assembler implementations (written in flat assembler), 
half of which were optimized for speed, the other half were optimized for size:

    small_fnv32:    ;FNV1 32bit (size: 31 bytes)
    ;                Intel Core 2 Duo E6600: 354.20 mb/s
       push    esi
       push    edi
       mov     esi, [esp + 0ch] ;buffer
       mov     ecx, [esp + 10h] ;length
       mov     eax, [esp + 14h] ;basis
       mov     edi, 01000193h   ;fnv_32_prime
     next:
       mul     edi
       xor     al, [esi]
       inc     esi
       loop    snext
       pop     edi
       pop     esi
       retn    0ch

     small_fnv32a:   ;FNV1a 32bit (size: 31 bytes)
    ;                 Intel Core 2 Duo E6600: 327.68 mb/s
       push    esi
       push    edi
       mov     esi, [esp + 0ch] ;buffer
       mov     ecx, [esp + 10h] ;length
       mov     eax, [esp + 14h] ;basis
       mov     edi, 01000193h   ;fnv_32_prime
     nexta:
       xor     al, [esi]
       mul     edi
       inc     esi
       loop    nexta
       pop     edi
       pop     esi
       retn    0ch

    fast_fnv32:    ;FNV1 32bit (size: 36 bytes)
    ;               Intel Core 2 Duo E6600: 565.12 mb/s
       push    ebx
       push    esi
       push    edi
       mov     esi, [esp + 10h] ;buffer
       mov     ecx, [esp + 14h] ;length
       mov     eax, [esp + 18h] ;basis
       mov     edi, 01000193h   ;fnv_32_prime
       xor     ebx, ebx
     next:
       mul     edi
       mov     bl, [esi]
       xor     eax, ebx
       inc     esi
       dec     ecx
       jnz     next
       pop     edi
       pop     esi
       pop     ebx
       retn    0ch

     fast_fnv32a:   ;FNV1a 32bit (size: 36 bytes)
    ;                Intel Core 2 Duo E6600: 574.95 mb/s
       push    ebx
       push    esi
       push    edi
       mov     esi, [esp + 10h] ;buffer
       mov     ecx, [esp + 14h] ;length
       mov     eax, [esp + 18h] ;basis
       mov     edi, 01000193h   ;fnv_32_prime
       xor     ebx, ebx
     nexta:
       mov     bl, [esi]
       xor     eax, ebx
       mul     edi
       inc     esi
       dec     ecx
       jnz     nexta
       pop     edi
       pop     esi
       pop     ebx
       retn    0ch
*/


/*
[FNV1A 'shift-less-&-xor-less' hash used in Leprechaun r.13+++:]

int FNV1A_Hash_SHIFTless_XORless(char *str)
{ 
u_int32_t hash;
char *p;

hash = FNV1_32_INIT;
for (p=str; *p; ++p) {
    hash = FNV_32A_OP(hash, *p);
}
//hash = ((hash>>13) ^ hash) & 8191; // (((u_int32_t)1<<(x))-1) where x=13

  return hash & 8191; // 00..8191 i.e. 2^13=8192
}

Words per second performance: 837,458W/s
Input File with a list of TEXTual Files: wikipedia-en-html.tar.wrd.lst
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2772875
Forest population(Hash Function Quality regarding Collisions i.e. Hash Table Utilization): 41%
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 9788999

Words per second performance: 1,007,751W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3537061
Forest population(Hash Function Quality regarding Collisions i.e. Hash Table Utilization): 53%
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 18665919

[My '2in1' hash used in Leprechaun r.13++:]

int KuxHash3plus(char *str)
{ int h = 0;
  unsigned long h2 = 0; // must be long: 31*'z'=31*122
  int max31 = 0;
  while (str[max31])
  { h = h ^ str[max31]; // 00..255 i.e. 2^8=256
    //h2 = h2 + str[max31++];       // [113s]
    h2 = h2 + str[max31++] * (max31+1);
  }
// Result is: 7bits in 'h' and 32bits in 'h2'.

                        //printf("%s:\n ",str);
                        //printf("%d ",h);
// a in ASCII is 097 = 0110 0001
// z in ASCII is 122 = 0111 1010
// Above two lines show that bits 8-7-6 are always 0-1-1 so need for low 5 bits.
  //h=h<<8; // 00..15 i.e. 5bits + 00-07bits=13bits
                        //printf("%d ",h);
                        //printf("%d ",h2);
  //h = h|( str[0] ^ str[max31-1] ); // [111s] a..z: each XOR each gives 00..31
  h = (( h<<8 )|( h2%(251) ))&8191; // 251 prime
                        //printf("%d \n",h);
  return h; // 00..8191 i.e. 2^13=8192
}

Words per second performance: 785,117W/s
Input File with a list of TEXTual Files: wikipedia-en-html.tar.wrd.lst
Word count: 12,561,874 of them 12,561,874 distinct
Number Of Trees(GREATER THE BETTER): 2663566
Forest population(Hash Function Quality regarding Collisions i.e. Hash Table Utilization): 40%
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 9898308

Words per second performance: 979,758W/s
Input File with a list of TEXTual Files: Leprechaun_vs_Wikipedia_LATIN-WORDS.lst
Word count: 35,271,297 of them 22,202,980 distinct
Number Of Trees(GREATER THE BETTER): 3410463
Forest population(Hash Function Quality regarding Collisions i.e. Hash Table Utilization): 51%
Number Of Hash Collisions(Distinct WORDs - Number Of Trees): 18792517

[Last standing for English(en)-Wikipedia's wordlist:]
chongo's hash is faster(in total, not the function itself) than Kaze's hash by ((837,458W/s - 785,117W/s)/785,117W/s)*100% = 6.6%
chongo's hash has better distribution than Kaze's hash by ((9898308 - 9788999)/9788999)*100% = 1.1%

[Last standing for LATIN(de,en,es,fr,it,nl,pt,ro)-Wikipedia's wordlist:]
chongo's hash is faster(in total, not the function itself) than Kaze's hash by ((1,007,751W/s - 979,758W/s)/979,758W/s)*100% = 2.8%
chongo's hash has better distribution than Kaze's hash by ((18792517 - 18665919)/18665919)*100% = 0.6%

Bottomline is:
Your hash thrash, my hash for trash, he-he.
Thanks a lot, again, Mr. Noll.

Yummy little file: http://www.isthe.com/chongo/src/fnv/fnv-5.0.2.tar.gz
*/


// The following example code in the C language computes the binary logarithm (rounding down) of an integer, rounded down. [2] The operator '>>' represents 'unsigned right shift'. The rounding down form of binary logarithm is identical to computing the position of the most significant 1 bit.
/**
 * Returns the floor form of binary logarithm for a 32 bit integer.
 * -1 is returned if n is 0.
 */
int floorLog2(unsigned int n) {
  int pos = 0;
  if (n >= 1<<16) { n >>= 16; pos += 16; }
  if (n >= 1<< 8) { n >>=  8; pos +=  8; }
  if (n >= 1<< 4) { n >>=  4; pos +=  4; }
  if (n >= 1<< 2) { n >>=  2; pos +=  2; }
  if (n >= 1<< 1) {           pos +=  1; }
  return ((n == 0) ? (-1) : pos);
}


int main( argc, argv )
int argc; char *argv[];
{
   int nlines;
   string *backup = NULL;

      FILE *fp_in, *fp_out, *fp_outLOG, *fp_inLINE;
      int LetterOffset;
      unsigned long long FilesLEN;
      unsigned long long WORDcount; 
      unsigned long long WORDcountAttemptsToPut; 
      int Thunderwith;
        unsigned long NumberOfFiles, WORDcountDistinct;
        unsigned long long NumberOfLines;  // rev. 12+
      unsigned long WHOLEletter_BufferSize;
        unsigned long memory_size, LetterBuffer, j, k, LINE10len, wrdlen;
        unsigned long long i;              // rev. 12+
        //unsigned long size_in, size_out, size_inLINE;
        unsigned long size_in;           // rev. 12+
#if defined(_WIN32_ENVIRONMENT_)
      unsigned long long size_inLINESIXFOUR;
#else
      size_t size_inLINESIXFOUR;
#endif /* defined(_WIN32_ENVIRONMENT_)  */

      //unsigned long t1, t2, t3;
      time_t t1, t2, t3;

      const int NumberOfSLOTs = 4096*2; // Since r.12+ in rev.12 it was 4096
  unsigned long StackPtr;
  unsigned long BSTstack [65536*3]; // BST in worst case could become a LL.
unsigned long NumberOfTrees=0, NumberOfHashCollisions=0;
unsigned long iBSTwithMAXpeak, jBSTwithMAXpeak;
  unsigned int PEAKibBST;
  unsigned long BSTsTotalLEAFs=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXnode=0, BSTcurrentNode=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long                   BSTcurrentNodeMAXqUANTITY=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXnodePEAK=1, BSTwithMAXnodeLEAF=1; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXpeak=0, BSTcurrentPeak=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long                   BSTcurrentPeakMAX=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long                   BSTcurrentPeakMAXqUANTITY=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXpeakNODE=1, BSTwithMAXpeakLEAF=1; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXleaf=0, BSTcurrentLeaf=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long                   BSTcurrentLeafMAXqUANTITY=0; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!
  unsigned long BSTwithMAXleafNODE=1, BSTwithMAXleafPEAK=1; // ?! MADHOUSE: if BSTcurrent is not zeroed here then INSANE values of BSTcurrent occur below where 'break' is ?!

      char *pointerflush, *BufStart, *Flushing;
      unsigned long PseudoLinkedPointer, PseudoLinkedPointerNEW, PseudoLinkedPointerROOT, PseudoLinkedPointerNEWold;
      unsigned long PseudoLinkedPointerNEWleft, PseudoLinkedPointerNEWright;
      unsigned long PseudoLinkedPointerNEWmiddle;
      char *bufend[ 806 ]; // 'a'=0, ... 'z'=25 - 26 letters x 31 lengths
      long bufNumberOfWords[ 806 ]; // 'a'=0, ... 'z'=25 - 26 letters x 31 lengths
      // long bufNoWpS[ 806 ][ 8192 ]; // ?! crashes below when an attempt to use it occur
      char wrd[32];  // 0..30, 31 = 0
      char wrdUP[32];  // 0..30, 31 = 0
      char wrdUPold[32];  // 0..30, 31 = 0
      char LINE10[257]; // 000..255, 256 = 0
      char ZEROS[4]; // 0..3, 0 = 0, 1 = 0, 2 = 0, 3 = 0
      char CRdLFa[2];  // 0..1, 0 = 13, 1 = 10
      char workbyte;
      char workK[1024*96];
      long workKoffset = -1;
      int FoundInLinkedList, Slot;
      unsigned long OffsetsInBuffer[31]; // 00..30
      unsigned long MAXusedBuffer[32]; // 00 not used, only 01..31
      unsigned long GRMBLhill[32]; // 00..31
      unsigned long GRMBLFoolAgain[32]; // 00..31
      int Melnitchka;
      unsigned long MAXusedBufferABS = 0;
      unsigned long Utiliza1 = 0;
      unsigned long Utiliza2 = 0;
      unsigned long TotalWLchars = 0;

/* minimum signed 64 bit value */
#define _I64_MIN    (-9223372036854775807i64 - 1)
/* maximum signed 64 bit value */
#define _I64_MAX      9223372036854775807i64
/* maximum unsigned 64 bit value */
#define _UI64_MAX     0xffffffffffffffffui64

/* minimum signed 128 bit value */
#define _I128_MIN   (-170141183460469231731687303715884105727i128 - 1)
/* maximum signed 128 bit value */
#define _I128_MAX     170141183460469231731687303715884105727i128
/* maximum unsigned 128 bit value */
#define _UI128_MAX    0xffffffffffffffffffffffffffffffffui128

      char llTOaDigits[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)
      // below duplicates are needed because of one_line_invoking need different buffers.
      char llTOaDigits2[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)
      char llTOaDigits3[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)
      char llTOaDigits4[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)
      unsigned long HEADOffetFromStartBUKVA = 0;
      unsigned long TAILOffetFromStartBUKVA = 0;
      int BSTorBtree = 0;
      int SplitOccured;
      int POffsetInLEAF;

// INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT INIT
puts( "Leprechaun(Fast Greedy Word-Ripper), revision 13+++++, written by Svalqyatchx." );
puts( "Leprechaun: 'Oh, well, didn't you hear? Bigger is good, but jumbo is dear.'" );
puts( "Kaze: Let's see what a 3-way hash + 6,602,752 Binary-Search-Trees can give us," );
puts( "      also the performance of a 3-way hash + 6,602,752 B-Trees of order 3." );
//puts( "Note1: Compiled with Microsoft C v. 13.10.3077: 'cl /Ox /TcLeprechaun.c'." );
//puts( "Note2: This WORDLISTER makes as output pseudo(unsorted)_wordlist_CRLF_file." );
if( argc != 3 && argc != 4 && argc != 5 && argc != 6 ) // +1 for program name
{
  puts( "" );
puts( "'The Little Monster' short notes:" );
puts( "Note1: I wish to thank to R.N. Horspool, Ranjan Sinha, Dmitry Shkarin," );
puts( "       Michael Abrash, J. Bentley, R. Sedgewick, Igor Pavlov, Lasse Reinhold," );
puts( "       Landon Noll for sharing their knowledge to public." );
puts( "Note2: Run it without parameters to get usage and short notes." );
puts( "Note3: This simple amateurish(more over I am not versed well neither in C nor" );
puts( "       in mathematics nor in english language, but I am persistent in INDEXING" );
puts( "       GBs of english TEXTS) tool is written in ANSI C(at least its source is" );
puts( "       compileable for CL(Windows) and GCC(Linux)), and its purpose is to" );
puts( "       create a WordList for a group of files(given via filelist)." );
puts( "       Its name comes(according to Heritage Dictionary) from 'low corpus' or" );
puts( "       'little body', in fact from amazing movie saga 'Leprechaun 1-2-3-4-5-6'" );
puts( "       starring by Warwick Davis." );
puts( "Note4: Only words up to 31 chars are proceeded - the reason is 'DDT'(the" );
puts( "       longest word in Heritage Dictionary 3rd edition) or" );
puts( "       'dichlorodiphenyltrichloroethane'." );
puts( "Note5: Cursor hiding in C - mission impossible for me." );
puts( "Note6: By default(third parameter is 1023) allocated memory is 393MB." );
puts( "       Due to 'malloc()' limitation under WINDOWS, maximum value of third" );
puts( "       parameter is 5174 which is 1988MB allocated block." );
puts( "Note7: File Leprechaun.LOG is a log, where new statistics are appended." );
puts( "Note8: Revision 12+ can handle files larger than 4GB." );
puts( "Note9: Revision 12++ has a buffered 'fread()' - therefore I/O READ-BURST SPEED" );
puts( "       is the first(worst) bottleneck, as a result r.12++ is much-much faster;" );
puts( "       the second(worse) bottleneck: the linked lists - the b-trees" );
puts( "       might be the answer; the third(bad) bottleneck: the amateurish author." );
puts( "NoteA: Revision 12+++ has an improved(2 bits were used doltishly) main hash" );
puts( "       function - therefore less collisions, for example:" );
puts( "       for file 'wikipedia-de-html.tar' 42,291,855,360 bytes with" );
puts( "       5,750,179,678 words of them 7,375,373 distinct attempts to Find/Put" );
puts( "       a WORD into a linked list are 6,117,675,470(r.12++) and 5,845,989,790" );
puts( "       (r.12+++); also two 'if' sections were moved because they were executed" );
puts( "       unnecessarily many times." );
puts( "NoteB: Revision 13 uses BSTs instead of LLs, that is Linked-Lists were" );
puts( "       replaced by Binary-Search-Trees, as a result for 22,202,980 distinct" );
puts( "       words(out of 35,271,297) r.12+++ needs 225,548,268 total attempts to" );
puts( "       Find/Put WORDs into linked lists where r.13 needs 121,674,042 total" );
puts( "       attempts to Find/Put WORDs into Binary-Search-Trees. But this is a" );
puts( "       significant boost in performance only for wordlists of million words." );
puts( "NoteC: Revision 13+ gives only more statistics. Future revisions could lessen" );
puts( "       number of attempts to Find/Put WORDs into Binary-Search-Trees" );
puts( "       furthermore by making them at some point Perfectly-Balanced. But" );
puts( "       for huge amount(multi-(m|b)illion) of distinct words the b-tree family" );
puts( "       must come in, until then this is the leprechaunish niche." );
puts( "NoteD: Revision 13++ has a little fix(2 unnecessary ZEROings, when a new word" );
puts( "       is inserted, were deleted) and a fixed bug(13+ adds stupidly the" );
puts( "       highest BST to the wordlist). Also B-Tree of order 3 is added as a" );
puts( "       searching method. Main goal of B-Tree is to reduce number of" );
puts( "       comparisons but at nasty cost: a precious time wasted to construct it" );
puts( "       and twice more memory, i.e. one step forward two backward: this tree is" );
puts( "       more effective than BST in cases of 2++ billion/million" );
puts( "       different/distinct words." );
puts( "       The improvement which comes from using B-Tree of order 3 is about 200%" );
puts( "       much more pleasing than I expected, for wikipedia-en-html.tar.wrd with" );
puts( "       12,561,874 distinct words Total Attempts to Find/Put WORDs into:" );
puts( "       Binary-Search-Trees was 61,895,043 while for" );
puts( "       B-trees order 3 was 19,295,791." );
puts( "NoteE: Revision 13+++ has a faster(not heavily tested yet) and with" );
puts( "       better(0.6% to 1.1%) dispersion Fowler/Noll/Vo hash," );
puts( "       so called FNV1a hash. Revision 13+++++ boosting: Leprechaun_Intel.exe" );
puts( "       gives 1,256,187W/s for wikipedia-en-html.tar.wrd with FNV1_32_PRIME:" );
puts( "       107712257 with 3,551,736 dispersion for 'FNV1A_Hash_Granularity'." );
puts( "NoteF: For old r.12+ a USB connected HDD crippled test:" );
puts( "       for 'H:\\>Leprechaun.exe static.wikipedia.org_downloads_2008-06_en.lst" );
puts( "       wikipedia-en-html.tar.wrd 5400'" );
puts( "       where 223,674,511,360 wikipedia-en-html.tar" );
puts( "       on laptop Toshiba Pentium T3400 2166 MHz with" );
puts( "       Motherboard Name:                             Toshiba Satellite L305" );
puts( "       CPU Type:         Mobile DualCore Intel Pentium, 2166 MHz (13 x 167)" );  
puts( "       CPU Alias:                                                  Merom-1M" );  
puts( "       L1 Code Cache:                                        32 KB per core" );  
puts( "       L1 Data Cache:                                        32 KB per core" );  
puts( "       L2 Cache:                        1 MB (On-Die, ECC, ASC, Full-Speed)" );  
puts( "       Bus Type:                                            Dual DDR2 SDRAM" );  
puts( "       Bus Width:                                                   128-bit" );  
puts( "       Real Clock:                                            333 MHz (DDR)" );  
puts( "       Effective Clock:                                             666 MHz" );
puts( "       EVEREST v5.00.1650 Memory Copy:       3725MB/s with timings 5-5-5-13" );
puts( "       result is logged to 'Leprechaun.LOG':" );
puts( "  Bytes per second performance: 20,658,955B/s" );
puts( "  Words per second performance: 2,860,880W/s" );
puts( "  Input File with a list of TEXTual Files:" );
puts( "   static.wikipedia.org_downloads_2008-06_en.lst" );
puts( "  Size of all TEXTual Files: 223,674,511,360" );
puts( "  Word count: 30,974,750,142 of them 12,561,874 distinct" );
puts( "  Number Of Files: 1" );
puts( "  Number Of Lines: 2088618575" );
puts( "  Allocated memory in MB: 1920" );
puts( "  Words with length 01 occupy 0,033KB of 0,349KB given i.e. 09% utilization" );
puts( "  Words with length 02 occupy 0,033KB of 0,349KB given i.e. 09% utilization" );
puts( "  Words with length 03 occupy 0,037KB of 0,697KB given i.e. 05% utilization" );
puts( "  Words with length 04 occupy 0,151KB of 0,871KB given i.e. 17% utilization" );
puts( "  Words with length 05 occupy 0,744KB of 1,568KB given i.e. 47% utilization" );
puts( "  Words with length 06 occupy 1,470KB of 3,136KB given i.e. 46% utilization" );
puts( "  Words with length 07 occupy 2,605KB of 5,923KB given i.e. 43% utilization" );
puts( "  Words with length 08 occupy 3,296KB of 6,968KB given i.e. 47% utilization" );
puts( "  Words with length 09 occupy 3,714KB of 6,968KB given i.e. 53% utilization" );
puts( "  Words with length 10 occupy 3,483KB of 6,968KB given i.e. 49% utilization" );
puts( "  Words with length 11 occupy 3,235KB of 5,923KB given i.e. 54% utilization" );
puts( "  Words with length 12 occupy 2,691KB of 4,181KB given i.e. 64% utilization" );
puts( "  Words with length 13 occupy 2,230KB of 3,484KB given i.e. 64% utilization" );
puts( "  Words with length 14 occupy 1,718KB of 3,484KB given i.e. 49% utilization" );
puts( "  Words with length 15 occupy 1,357KB of 2,613KB given i.e. 51% utilization" );
puts( "  Words with length 16 occupy 1,063KB of 2,613KB given i.e. 40% utilization" );
puts( "  Words with length 17 occupy 0,814KB of 1,742KB given i.e. 46% utilization" );
puts( "  Words with length 18 occupy 0,617KB of 1,742KB given i.e. 35% utilization" );
puts( "  Words with length 19 occupy 0,485KB of 1,742KB given i.e. 27% utilization" );
puts( "  Words with length 20 occupy 0,402KB of 1,742KB given i.e. 23% utilization" );
puts( "  Words with length 21 occupy 0,327KB of 1,742KB given i.e. 18% utilization" );
puts( "  Words with length 22 occupy 0,274KB of 1,742KB given i.e. 15% utilization" );
puts( "  Words with length 23 occupy 0,224KB of 1,394KB given i.e. 16% utilization" );
puts( "  Words with length 24 occupy 0,190KB of 1,394KB given i.e. 13% utilization" );
puts( "  Words with length 25 occupy 0,162KB of 1,394KB given i.e. 11% utilization" );
puts( "  Words with length 26 occupy 0,136KB of 1,220KB given i.e. 11% utilization" );
puts( "  Words with length 27 occupy 0,119KB of 1,046KB given i.e. 11% utilization" );
puts( "  Words with length 28 occupy 0,107KB of 0,871KB given i.e. 12% utilization" );
puts( "  Words with length 29 occupy 0,091KB of 0,697KB given i.e. 13% utilization" );
puts( "  Words with length 30 occupy 0,080KB of 0,523KB given i.e. 15% utilization" );
puts( "  Words with length 31 occupy 0,076KB of 0,523KB given i.e. 14% utilization" );
puts( "  Total pseudo(including hash table) memory utilization: 42%" );
puts( "  Total real(wordlist's words VS allocated block) memory utilization: 60/1000" );
puts( "  Used value for third parameter in KB: 5400" );
puts( "  Use next time as third parameter: 3475-" );
puts( "  Time for making unsorted wordlist: 10827 second(s)" );
puts( "  Time for sorting unsorted wordlist: 10 second(s)" );

  puts( "" );
  puts( "Usage: Leprechaun InFile OutFile [BufferSize] [SortMethod] [TreeMethod]" );
  puts( "      <InFile>: Input file with files for Leprechauning, in WINDOWS console" );
  puts( "                you can create it by 'E:\\KAZEHOME>dir *.txt/s/b>Leprechaun.lst'" );
  puts( "      <OutFile>: Output WORDLIST(sorted since r.9, CRLF) file" );
  puts( "      <BufferSize>: Optional Dynamic RAM buffer in KB, default(and minimum" );
  puts( "                    in the same time) is 1023, i.e. omit or specify greater one" );
  puts( "      <SortMethod>: Optional Sort Method, default is 'D'," );
  puts( "                    A - InsertionSort" );
  puts( "                    B - InsertionX26Sort" );
  puts( "                    C - MultiKeyQuickSortSort by J. Bentley, R. Sedgewick" );
  puts( "                    D - MultiKeyQuickSortX26Sort' by J. Bentley, R. Sedgewick" );
  puts( "      <TreeMethod>: Optional Tree Method, default is 'X'," );
  puts( "                    X - Binary-Search-Trees" );
  puts( "                    Y - B-Trees of order 3" );
  puts( "" );
puts( "Have a nice Leprechauning." );
puts( "For contacts: sanmayce@sanmayce.com" );
puts( "Sanmayce Svalqyatchx 'Kaze', 2005 Feb 07(rev.13+++++: 2010 Aug 27)." );
  return( 1 );
}

  GRMBLhill[0]=0;
  GRMBLhill[1]=1;
  GRMBLhill[2]=1;
  GRMBLhill[3]=1;
  GRMBLhill[4]=4;
  GRMBLhill[5]=11;
  GRMBLhill[6]=22;
  GRMBLhill[7]=37;
  GRMBLhill[8]=47;
  GRMBLhill[9]=53;
  GRMBLhill[10]=50;
  GRMBLhill[11]=46;
  GRMBLhill[12]=38;
  GRMBLhill[13]=32;
  GRMBLhill[14]=25;
  GRMBLhill[15]=20;
  GRMBLhill[16]=18;
  GRMBLhill[17]=14;
  GRMBLhill[18]=10;
  GRMBLhill[19]=8;
  GRMBLhill[20]=7;
  GRMBLhill[21]=6;
  GRMBLhill[22]=5;
  GRMBLhill[23]=4;
  GRMBLhill[24]=3;
  GRMBLhill[25]=3;
  GRMBLhill[26]=2;
  GRMBLhill[27]=2;
  GRMBLhill[28]=2;
  GRMBLhill[29]=2;
  GRMBLhill[30]=1;
  GRMBLhill[31]=1;

if( ( fp_in = fopen( argv[1], "rb" ) ) == NULL )
{ printf( "Leprechaun: Can't open file %s \n", argv[1] ); return( 1 ); }

fseek( fp_in, 0L, SEEK_END );
size_in = ftell( fp_in );
fseek( fp_in, 0L, SEEK_SET );
printf( "Size of input file with files for Leprechauning: %lu\n", size_in );

if( ( fp_outLOG = fopen( "Leprechaun.LOG", "a+" ) ) == NULL )
{ printf( "Leprechaun: Can't open file Leprechaun.LOG.\n" ); return( 1 ); }

// argc is 4|5|6 due to eventual missing BufferSize
if( argc == 4 ) // not 6 due to eventual missing BufferSize and SortMethod
    k = 3;
if( argc == 5)  // not 6 due to eventual missing BufferSize or SortMethod
    k = 4;
if( argc == 6 )  
    k = 5;
if (*argv[k] == 'Y' || *argv[k] == 'y') BSTorBtree = 1;

if( argc == 4 || argc == 5 || argc == 6 ) Thunderwith = atoi( argv[3] );
else Thunderwith = 527; // for r.12:   527=17*31 this is minimum because of 4096*1*4=16KB+ needed for each buffer!
                        // for r.12+: 1023=33*31 this is minimum because of 4096*2*4=32KB+ needed for each buffer!
if (Thunderwith < 1023) {Thunderwith = 1023;}
LetterBuffer = Thunderwith * 1024;
  WHOLEletter_BufferSize = 0;
  for( i = 1; i <= 31; i++ )
  { OffsetsInBuffer[i-1] = 0;
    for( j = 1; j <= i; j++ )
    { OffsetsInBuffer[i-1] = OffsetsInBuffer[i-1] + (GRMBLhill[(int)(j-1)] * LetterBuffer)/31;
    }
    WHOLEletter_BufferSize = WHOLEletter_BufferSize + (GRMBLhill[(int)i] * LetterBuffer)/31; // Make soon 32 in order to shift >>5
    GRMBLFoolAgain[(int)i] = (GRMBLhill[(int)i] * LetterBuffer)/31;
  }                           
  memory_size = 26 * WHOLEletter_BufferSize + 1;
pointerflush = (char *)malloc( memory_size );
if( pointerflush == NULL )
{ puts( "Leprechaun: Needed memory allocation denied!\n" ); return( 1 ); }

                  fprintf( fp_outLOG, "Leprechaun report:\n" );

printf( "Allocated memory in MB: %lu\n", (memory_size>>20)+1 );

// Check once for ever whether allocated memory is ZEROed!? Answer: YES
//for( i = 0; i < memory_size; i++ )
// if (*(char *)(pointerflush+i)!=0) printf("NON-ZERO encountered, so 'NO'.");

for( i = 0; i < 26; i++ )
{ for( k = 1; k <= 31; k++ )
  { bufend[i*31+k-1] = pointerflush + i * WHOLEletter_BufferSize + OffsetsInBuffer[k-1]; // i*31+k-1 must be 0..805
        if (i==25) { MAXusedBuffer[k] = (unsigned long)bufend[i*31+k-1]; }
    for( j = 0; j < (NumberOfSLOTs+1)*4; j++ ) // ? memset(bufend[i],0,(NumberOfSLOTs+1)*4);
    { *bufend[i*31+k-1]++ = 0;
      //++bufend[i*31+k-1];
    }   
        if (i==25) { MAXusedBuffer[k] = (unsigned long)bufend[i*31+k-1]-MAXusedBuffer[k]; }
    bufNumberOfWords[i*31+k-1]=0;
//for( j = 0; j < NumberOfSLOTs; j++ )
//bufNoWpS[i*31+k-1][j]=0;
  }
}

// PROGRAM PROGRAM PROGRAM PROGRAM PROGRAM PROGRAM PROGRAM PROGRAM PROGRAM
(void) time(&t1);
        Melnitchka = 0;
        WORDcount = 0; // Total word count i.e. for all files!
        WORDcountDistinct = 0;
        NumberOfFiles = 0;
        NumberOfLines = 0;
        FilesLEN = 0;
        LINE10len = 0;

        for( k = 0; k < size_in; k++ )
	{
                fread( &workbyte, 1, 1, fp_in );
                if( workbyte != 10 )
                { if( workbyte != 13 ) // NON UNIX
                  { if( LINE10len < 255 ) { LINE10[ LINE10len ] = workbyte; }
                    LINE10len++;
                  }
                  else
                  {
                  }
		}
		else
                { if( 1 <= LINE10len && LINE10len <= 255 )
                  { LINE10[ LINE10len ] = 0;
if( ( fp_inLINE = fopen( LINE10, "rb" ) ) == NULL )
{ printf( "Leprechaun: Can't open file %s \n", LINE10 ); return( 1 ); }

//fseek( fp_inLINE, 0L, SEEK_END );  //Rev. 12
//size_inLINE = ftell( fp_inLINE );  //Rev. 12
//fseek( fp_inLINE, 0L, SEEK_SET );  //Rev. 12

#if defined(_WIN32_ENVIRONMENT_)
   // 64bit:
_lseeki64( fileno(fp_inLINE), 0L, SEEK_END );
size_inLINESIXFOUR = _telli64( fileno(fp_inLINE) );
_lseeki64( fileno(fp_inLINE), 0L, SEEK_SET );
#else
   // 64bit:
fseeko( fp_inLINE, 0L, SEEK_END );
size_inLINESIXFOUR = ftello( fp_inLINE );
fseeko( fp_inLINE, 0L, SEEK_SET );
#endif /* defined(_WIN32_ENVIRONMENT_)  */

printf( "Size of Input TEXTual file: %s\n", _ui64toaKAZEcomma(size_inLINESIXFOUR, llTOaDigits, 10) );
FilesLEN = FilesLEN + size_inLINESIXFOUR;
NumberOfFiles++;

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	wrdlen = 0;
        for( i = 0; i < size_inLINESIXFOUR; i++ )
	{

                // ~~~~~~~~~~~~ Buffering fread [
                if (workKoffset == -1) {
                        if (i + 1024*96 < size_inLINESIXFOUR) {
                                fread( &workK[0], 1, 1024*96, fp_inLINE );
                                workKoffset = 0;
                                workbyte = workK[workKoffset];
                        } else 
                        fread( &workbyte, 1, 1, fp_inLINE );
                } else {
                        workKoffset++;
                        workbyte = workK[workKoffset];
                        if (workKoffset == 1024*96 - 1) workKoffset = -1;
                }
                // ~~~~~~~~~~~~ Buffering fread ]

//                if( isalpha( workbyte ) )
//                {
//                        if( wrdlen < 31 )
//                        { wrd[ wrdlen ] = tolower( workbyte ); }
//                        wrdlen++;
//                }

                if ( workbyte < 'A' ) // Most characters are uneder alphabet - only one if
                {
ElStupido:
                        // This fragment is MIRRORed: #1 copy [
                        if (workbyte == 10) {NumberOfLines++;}
                        if( 1 <= wrdlen && wrdlen <= 31 )
			{
                                wrd[ wrdlen ] = 0;
                                // OTKACHAM: 1<<17-1 gives 65536 i.e. '-' have had high priority than '<<'
                                //Next line gives error due to mix of '&' and 'double' 
                                if ((++WORDcount & ((1<<20)-1)) == 0)
                                { //_ui64toaKAZEzerocomma(WORDcount, llTOaDigits, 10);
                                  //printf( "Word count: %s(%lu/128 done)\r", llTOaDigits, ((long long)i*100) / size_inLINESIXFOUR );
++Melnitchka;
Melnitchka = Melnitchka % 4;
if (Melnitchka == 0){ printf( "|; Word count: %s of them %s distinct; Done: %lu/64\r", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), ((long long)i<<6) / size_inLINESIXFOUR ); }
if (Melnitchka == 1){ printf( "/; Word count: %s of them %s distinct; Done: %lu/64\r", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), ((long long)i<<6) / size_inLINESIXFOUR ); }
if (Melnitchka == 2){ printf( "-; Word count: %s of them %s distinct; Done: %lu/64\r", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), ((long long)i<<6) / size_inLINESIXFOUR ); }
if (Melnitchka == 3){ printf( "\\; Word count: %s of them %s distinct; Done: %lu/64\r", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), ((long long)i<<6) / size_inLINESIXFOUR ); }
                                }
  LetterOffset = (int)( wrd[0] - 'a' ) * 31 + (wrdlen-1); // 0..805
  //BufStart = pointerflush + LetterOffset * LetterBuffer; // OLD

  BufStart = pointerflush + (int)( wrd[0] - 'a' ) * WHOLEletter_BufferSize + OffsetsInBuffer[wrdlen-1];
  // Above line and Below line are equal
  //BufStart = pointerflush + (LetterOffset / 31) * WHOLEletter_BufferSize + OffsetsInBuffer[LetterOffset % 31];

              //Slot = KuxHash3plus(wrd)<<2; //13++
              //Slot = FNV1A_Hash_SHIFTless_XORless(wrd)<<2; //13+++
              //Slot = FNV1A_Hash_4_OCTETS(wrd, wrdlen>>2)<<2; //13++++
              //Slot = FNV1A_Hash_4_OCTETS_31(wrd, wrdlen>>2)<<2; //13+++++
/*
if (wrdlen<=19) // 4x4+3=19
              Slot = FNV1A_Hash_4_OCTETS(wrd, wrdlen>>2)<<2; //13++++
else            // 2x8+4=20 i.e. first contains 5 clashes
              Slot = FNV1A_Hash_8_OCTETS(wrd, wrdlen>>3)<<2; //13+++++
*/
if (wrdlen<=19) // 4x4+3=19 i.e. last contains 7 clashes
              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>2, 2)<<2; //13+++++
else            // 2x8+4=20 i.e. first contains 6 clashes
              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>3, 3)<<2; //13+++++

                    memcpy( &PseudoLinkedPointer, BufStart+Slot, 4 );
//; Line 917
//  mov     edx, DWORD PTR [eax+ebp]
//  add     esp, 4
                    // ?! DANGEROUS: above and below lines are(must:long must be 4bytes) identical
                    //PseudoLinkedPointer = (unsigned long)*(long *)(BufStart+Slot);
//; Line 919
//  mov     edx, DWORD PTR [eax+ebp]
//  add     esp, 4
                    //        while (count--) {
                    //        *(char *)dst = *(char *)src;
                    //        dst = (char *)dst + 1;
                    //        src = (char *)src + 1;
                    //        }
if (BSTorBtree != 1)
{
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ BST fragment [
                    if (PseudoLinkedPointer == 0) // means EMPTY-SLOT
                    {
            //if( (unsigned long)(bufend[LetterOffset] - BufStart) + wrdlen + 4 < (GRMBLhill[(int)wrdlen] * LetterBuffer)/31 ) // OLD slower
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + wrdlen + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] ) // +4 more for BST instead of LL
                      {
                      memcpy( BufStart+Slot, &bufend[LetterOffset], 4 );
//; Line 932
//  mov     DWORD PTR [eax+ebp], esi
                      // ?! DANGEROUS: above and below lines are(must:long must be 4bytes) identical
                      //*(long *)(BufStart+Slot) = *(long *)&bufend[LetterOffset];
//; Line 936
//  mov     DWORD PTR [eax+ebp], esi

                      // Below 3 lines are commented due to experiment below malloc which shows that allocated memory is ZEROed.
                      //memcpy( bufend[LetterOffset], &BufStart[NumberOfSLOTs*4], 4 ); // means next exists not: Means PseudoLinkedPointerL = 0
//; Line 940
//  mov     ecx, DWORD PTR [ebp+32768]
                      // ?! DANGEROUS: above and below lines are(must:long must be 4bytes) identical
                      //*(long *)bufend[LetterOffset] = *(long *)&BufStart[NumberOfSLOTs*4];
//; Line 944
//  mov     ecx, DWORD PTR [ebp+32768]
                      //bufend[LetterOffset] = bufend[LetterOffset] + 4;
                      //memcpy( bufend[LetterOffset], &BufStart[NumberOfSLOTs*4], 4 ); // means next exists not: Means PseudoLinkedPointerR = 0
                      bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4; // + 4 due to above commenting
                      memcpy( bufend[LetterOffset], wrd, wrdlen ); WORDcountDistinct++; bufNumberOfWords[LetterOffset]++;
                                //bufNoWpS[LetterOffset][Slot]++; // ?! crashes
                      bufend[LetterOffset] = bufend[LetterOffset] + wrdlen;
                      if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                      }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into Binary-Search-Trees: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
                    }
                    else // means USED-SLOT
                    { FoundInLinkedList = 0;
                      while (PseudoLinkedPointer != 0 && FoundInLinkedList == 0)
                      { 
                        if (memcmp(PseudoLinkedPointer+4+4,wrd,wrdlen) == 0)
                    //        while ( --count && *(char *)buf1 == *(char *)buf2 ) {
                    //        buf1 = (char *)buf1 + 1;
                    //        buf2 = (char *)buf2 + 1;
                    //        }
                    //        return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
                        { FoundInLinkedList = 1;
                        }
                        else // i.e < or >
                        {
                          if (memcmp(PseudoLinkedPointer+4+4,wrd,wrdlen) > 0)
                          memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer, 4 );
                          else
                          {
                          PseudoLinkedPointer = PseudoLinkedPointer + 4;
                          memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer, 4 );
                          }

                          if (PseudoLinkedPointerNEW == 0)
                    {
            //if( (unsigned long)(bufend[LetterOffset] - BufStart) + wrdlen + 4 < (GRMBLhill[(int)wrdlen] * LetterBuffer)/31 ) // OLD slower
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + wrdlen + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] )
                          { memcpy( PseudoLinkedPointer, &bufend[LetterOffset], 4 );
                            // Below 3 lines are commented due to experiment below malloc which shows that allocated memory is ZEROed.
                            //memcpy( bufend[LetterOffset], &BufStart[NumberOfSLOTs*4], 4 ); // means next exists not
                            //bufend[LetterOffset] = bufend[LetterOffset] + 4;
                            //memcpy( bufend[LetterOffset], &BufStart[NumberOfSLOTs*4], 4 ); // means next exists not
                            bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4; // + 4 due to above commenting
                            memcpy( bufend[LetterOffset], wrd, wrdlen ); WORDcountDistinct++; bufNumberOfWords[LetterOffset]++;
                                //bufNoWpS[LetterOffset][Slot]++; // ?! crashes
                             bufend[LetterOffset] = bufend[LetterOffset] + wrdlen;
                            if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                          }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into Binary-Search-Trees: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
                    }
                          PseudoLinkedPointer = PseudoLinkedPointerNEW;
                        }
                        WORDcountAttemptsToPut++;
                      } // while
                    }
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ BST fragment ]
} else
{
// ########################################## B-tree order 3 fragment [
//
// LEAF structure: [LeftPointer][MiddlePointer][RightPointer][LeftWord][RightWord]
//                  4bytes       4bytes         4bytes        wrdlen    wrdlen
//                                                            *         *          <- if *(char *)==0 means the word cell is empty
// ALL B-tree order 3 fragment consists of 3 sub-fragments:
// 1] Search 2] if Search failed Trasirascht(pushing in stack PseudoLinkedPointer(visited LEAFs)) Search 3] Insert Iterative

// 1] Search [ ________1407 line in C - see below: whole Search in assembler________
                    if (PseudoLinkedPointer == 0) // means EMPTY-SLOT
                    {
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + 2*wrdlen + 4 + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] ) // +4 more for BST instead of LL; + more(see LEAF)
                      {
                      memcpy( BufStart+Slot, &bufend[LetterOffset], 4 );
                      bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4 + 4; // + 4 due to above commenting
                      memcpy( bufend[LetterOffset], wrd, wrdlen ); WORDcountDistinct++; bufNumberOfWords[LetterOffset]++;
                      bufend[LetterOffset] = bufend[LetterOffset] + 2*wrdlen;
                      if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                      }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into B-trees order 3: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
                      FoundInLinkedList = 1;
                    }
                    else // means USED-SLOT
                    { FoundInLinkedList = 0;
                      while (PseudoLinkedPointer != 0 && FoundInLinkedList == 0)
                      { 
// ***** 'P W P' section [
// LW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
// RW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        // here ALWAYS LW exists: no need for existence check - line below
                        // if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
                        if (memcmp(PseudoLinkedPointer+4+4+4,wrd,wrdlen) > 0) // go LP
                           { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 0, 4 ); //LP
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else if (memcmp(PseudoLinkedPointer+4+4+4,wrd,wrdlen) < 0) // go RP or MP
                           { // RW existence check - line below:
                             if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 ) // RW exists
                                { // Here all 'P W P' section is repeated; the way of handling case when dynamic number of words in leaf
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ***** 'P W P' section 2 [
// LW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
// RW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        // here ALWAYS RW exists: no need for existence check - line below
                        // if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        if (memcmp(PseudoLinkedPointer+4+4+4+wrdlen,wrd,wrdlen) > 0) // go MP
                           { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4, 4 ); //MP
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else if (memcmp(PseudoLinkedPointer+4+4+4+wrdlen,wrd,wrdlen) < 0) // go RP
                           { // No ?W after RW - go RP
                             memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4 + 4, 4 ); //RP
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else FoundInLinkedList = 1; // wrd is RW
                        WORDcountAttemptsToPut++;
// ***** 'P W P' section 2 ]
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                }
                             else // RW empty - go MP
                                { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4, 4 ); //MP
                                  PseudoLinkedPointer = PseudoLinkedPointerNEW;
                                }
                           }
                        else FoundInLinkedList = 1; // wrd is LW
                        WORDcountAttemptsToPut++;
// ***** 'P W P' section ]
                      } // while
                        WORDcountAttemptsToPut--; // - 1 due to BST way of counting i.e. direct hash hit is not counted only successors
                    }
// 1] Search ] ________1484 line in C - see below: whole Search in assembler________

/*
; Line 1397
	jmp	$L2139
$L2042:
; Line 1408
	test	edx, edx
	jne	SHORT $L2110
; Line 1410
	mov	ecx, DWORD PTR _bufend$[esp+esi*4+892340]
	mov	edi, DWORD PTR _GRMBLFoolAgain$[esp+ebx*4+892340]
	lea	edx, DWORD PTR _bufend$[esp+esi*4+892340]
	lea	esi, DWORD PTR [ebx+ebx+12]
	sub	esi, ebp
	add	esi, ecx
	cmp	esi, edi
	mov	DWORD PTR tv4122[esp+892340], edx
	jae	$L2113
; Line 1412
	mov	DWORD PTR [eax+ebp], ecx
; Line 1413
	lea	eax, DWORD PTR [ecx+12]
; Line 1436
	jmp	$L2749
$L2110:
; Line 1437
	mov	DWORD PTR _FoundInLinkedList$[esp+892340], 0
	npad	11
$L2141:
; Line 1438
	mov	eax, DWORD PTR _FoundInLinkedList$[esp+892340]
	test	eax, eax
	jne	$L2142
; Line 1445
	lea	ebp, DWORD PTR [edx+12]
	mov	ecx, ebx
	lea	edi, DWORD PTR _wrd$[esp+892340]
	mov	esi, ebp
	xor	eax, eax
	repe cmpsb
	je	SHORT $L2682
	sbb	eax, eax
	sbb	eax, -1
$L2682:
	test	eax, eax
	jle	SHORT $L2143
; Line 1447
	mov	edx, DWORD PTR [edx]
; Line 1449
	jmp	$L2153
$L2143:
	mov	ecx, ebx
	lea	edi, DWORD PTR _wrd$[esp+892340]
	mov	esi, ebp
	xor	eax, eax
	repe cmpsb
	je	SHORT $L2640
	sbb	eax, eax
	sbb	eax, -1
$L2640:
	test	eax, eax
	jge	SHORT $L2145
; Line 1451
	mov	cl, BYTE PTR [edx+ebx+12]
	test	cl, cl
	lea	eax, DWORD PTR [edx+ebx+12]
	je	SHORT $L2147
; Line 1459
	mov	ecx, ebx
	lea	edi, DWORD PTR _wrd$[esp+892340]
	mov	esi, eax
	xor	ebp, ebp
	repe cmpsb
	je	SHORT $L2695
	sbb	ebp, ebp
	sbb	ebp, -1
$L2695:
	test	ebp, ebp
	jle	SHORT $L2148
; Line 1461
	mov	edx, DWORD PTR [edx+4]
; Line 1463
	jmp	SHORT $L2151
$L2148:
	mov	esi, eax
	mov	ecx, ebx
	lea	edi, DWORD PTR _wrd$[esp+892340]
	xor	eax, eax
	repe cmpsb
	je	SHORT $L2642
	sbb	eax, eax
	sbb	eax, -1
$L2642:
	test	eax, eax
	jge	SHORT $L2150
; Line 1466
	mov	edx, DWORD PTR [edx+8]
; Line 1468
	jmp	SHORT $L2151
$L2150:
	mov	DWORD PTR _FoundInLinkedList$[esp+892340], 1
$L2151:
; Line 1469
	mov	ecx, DWORD PTR _WORDcountAttemptsToPut$[esp+892340]
	mov	eax, DWORD PTR _WORDcountAttemptsToPut$[esp+892344]
	add	ecx, 1
	adc	eax, 0
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892340], ecx
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892344], eax
; Line 1473
	jmp	SHORT $L2153
$L2147:
; Line 1475
	mov	edx, DWORD PTR [edx+4]
; Line 1478
	jmp	SHORT $L2153
$L2145:
	mov	DWORD PTR _FoundInLinkedList$[esp+892340], 1
$L2153:
; Line 1479
	mov	esi, DWORD PTR _WORDcountAttemptsToPut$[esp+892340]
	mov	ecx, DWORD PTR _WORDcountAttemptsToPut$[esp+892344]
	add	esi, 1
	adc	ecx, 0
	test	edx, edx
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892340], esi
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892344], ecx
	jne	$L2141
$L2142:
; Line 1482
	mov	edx, DWORD PTR _WORDcountAttemptsToPut$[esp+892340]
	mov	ecx, DWORD PTR _WORDcountAttemptsToPut$[esp+892344]
	or	eax, -1
	add	edx, eax
	adc	ecx, eax
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892344], ecx
	mov	DWORD PTR _WORDcountAttemptsToPut$[esp+892340], edx
$L2139:
*/

if (FoundInLinkedList == 0)
{
// 2] if Search failed Trasirascht(pushing in stack PseudoLinkedPointer(visited LEAFs)) Search [
//    'TracingSearch' is the same as 'Search' except that adds the trail in my simulated stack,
//    the goal is not to waste time in 'Search' by dealing with no needed trail in case of not 'Insert'.
//    Simulated stack contains pairs of 'Address of ParentLEAF' + 'Offset of ParentPointer in ParentLEAF i.e. 0 for LP, 4 for MP, 8 for RP'.
//    'Offset ...' saves unnecessary comparisons of NEWword which after splitting goes up.
                    memcpy( &PseudoLinkedPointer, BufStart+Slot, 4 );
                StackPtr = 0;
                      while (PseudoLinkedPointer != 0)
                      { 
// ***** 'P W P' section [
// LW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
// RW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        // here ALWAYS LW exists: no need for existence check - line below
                        // if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
                        if (memcmp(PseudoLinkedPointer+4+4+4,wrd,wrdlen) > 0) // go LP
                           { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 0, 4 ); //LP
                if (StackPtr > 65536*3-1-1) { printf( "\nLeprechaun: Failure! 'B-tree order 3' simulated stack overflow!\n" ); return( 13 );}
                BSTstack[StackPtr] = PseudoLinkedPointer; ++StackPtr; //pt to visited leaf
                BSTstack[StackPtr] = 0; ++StackPtr; //LPoffset=0;MPoffset=4;RPoffset=8;
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else if (memcmp(PseudoLinkedPointer+4+4+4,wrd,wrdlen) < 0) // go RP or MP
                           { // RW existence check - line below:
                             if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 ) // RW exists
                                { // Here all 'P W P' section is repeated; the way of handling case when dynamic number of words in leaf
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ***** 'P W P' section 2 [
// LW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4) != 0 )
// RW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        // here ALWAYS RW exists: no need for existence check - line below
                        // if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
                        if (memcmp(PseudoLinkedPointer+4+4+4+wrdlen,wrd,wrdlen) > 0) // go MP
                           { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4, 4 ); //MP
                if (StackPtr > 65536*3-1-1) { printf( "\nLeprechaun: Failure! 'B-tree order 3' simulated stack overflow!\n" ); return( 13 );}
                BSTstack[StackPtr] = PseudoLinkedPointer; ++StackPtr; //pt to visited leaf
                BSTstack[StackPtr] = 4; ++StackPtr; //LPoffset=0;MPoffset=4;RPoffset=8;
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else if (memcmp(PseudoLinkedPointer+4+4+4+wrdlen,wrd,wrdlen) < 0) // go RP
                           { // No ?W after RW - go RP
                             memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4 + 4, 4 ); //RP
                if (StackPtr > 65536*3-1-1) { printf( "\nLeprechaun: Failure! 'B-tree order 3' simulated stack overflow!\n" ); return( 13 );}
                BSTstack[StackPtr] = PseudoLinkedPointer; ++StackPtr; //pt to visited leaf
                BSTstack[StackPtr] = 8; ++StackPtr; //LPoffset=0;MPoffset=4;RPoffset=8;
                             PseudoLinkedPointer = PseudoLinkedPointerNEW;
                           }
                        else FoundInLinkedList = 1; // wrd is RW
// ***** 'P W P' section 2 ]
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                }
                             else // RW empty - go MP
                                { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer + 4, 4 ); //MP
                if (StackPtr > 65536*3-1-1) { printf( "\nLeprechaun: Failure! 'B-tree order 3' simulated stack overflow!\n" ); return( 13 );}
                BSTstack[StackPtr] = PseudoLinkedPointer; ++StackPtr; //pt to visited leaf
                BSTstack[StackPtr] = 4; ++StackPtr; //LPoffset=0;MPoffset=4;RPoffset=8;
                                  PseudoLinkedPointer = PseudoLinkedPointerNEW;
                                }
                           }
                        else FoundInLinkedList = 1; // wrd is LW
// ***** 'P W P' section ]
                      } // while
// 2] if Search failed Trasirascht(pushing in stack PseudoLinkedPointer(visited LEAFs)) Search ]

// 3] Insert Iterative [
//    There are total 4 situations:
//    Case #1: Outer NODE(including ROOT) [  ][  ][  ][LW][  ]
//    Case #2: Outer NODE(including ROOT) [  ][  ][  ][LW][RW]  Split Occurs   -----  
//    Case #3: ROOT                       [LP][MP][  ][LW][  ]                     |  'wrdUP' (wrdlen bytes) 
//    Case #4: Inner NODE(including ROOT) [LP][MP][RP][LW][RW]  Split Occurs   --- |   &
//                                                                               | |  'PseudoLinkedPointerNEW' (ptr to NEW LEAF)
//    There are total 2 situations for PARENT LEAF: <-------------------------------  ARE GOING UP
//    Case #3: [LP][MP][  ][LW][  ]  
//    Case #4: [LP][MP][RP][LW][RW]  Split Occurs

// ~  First deal alonely with the OUTER NODE(LEAF) where Search stopped i.e Case #1 & Case #2:
        POffsetInLEAF = BSTstack[--StackPtr];
        PseudoLinkedPointer = BSTstack[--StackPtr];
// NOTE: ONE LEAF IS FULL ONLY WHEN LAST CELL FOR KEY(here RW) EXISTS!
// RW: existence check if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 )
if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 ) // If LEAF is full: Case #2
    { SplitOccured = 1; WORDcountDistinct++; bufNumberOfWords[LetterOffset]++;
            // ALlocate NEW LEAF:
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + 2*wrdlen + 4 + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] ) // +4 more for BST instead of LL; + more(see LEAF)
                      {
                      memcpy( &PseudoLinkedPointerNEW, &bufend[LetterOffset], 4 );
                      bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4 + 4; // + 4 due to above commenting
                      bufend[LetterOffset] = bufend[LetterOffset] + 2*wrdlen;
                      if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                      }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into B-trees order 3: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
      if (POffsetInLEAF == 0) // wrd < LW
         {
                      memcpy( wrdUP, PseudoLinkedPointer+4+4+4, wrdlen ); // LW up
                      memcpy( PseudoLinkedPointer+4+4+4, wrd, wrdlen );   // wrd go to OLD LEAF
                      memcpy( PseudoLinkedPointerNEW+4+4+4, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW go to NEW LEAF
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
         }
      if (POffsetInLEAF == 4) // LW < wrd < RW
         {
                      memcpy( wrdUP, wrd, wrdlen );                       // wrd up
                      memcpy( PseudoLinkedPointerNEW+4+4+4, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW go to NEW LEAF
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
         }
      if (POffsetInLEAF == 8) // wrd > RW
         {
                      memcpy( wrdUP, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW up
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
                      memcpy( PseudoLinkedPointerNEW+4+4+4, wrd, wrdlen );   // wrd go to NEW LEAF
         }
    }
else // If LEAF is not full: Case #1
    { SplitOccured = 0; WORDcountDistinct++; bufNumberOfWords[LetterOffset]++;
      if (POffsetInLEAF == 0) // wrd < [LW][] so [LW][] -> [][LW] -> [wrd][LW]
         {
                      memcpy( PseudoLinkedPointer+4+4+4+wrdlen, PseudoLinkedPointer+4+4+4, wrdlen );
                      memcpy( PseudoLinkedPointer+4+4+4, wrd, wrdlen );
         }
      if (POffsetInLEAF == 4) // wrd > [LW][] so [LW][] -> [LW][wrd]
         {
                      memcpy( PseudoLinkedPointer+4+4+4+wrdlen, wrd, wrdlen );
         }
    }

if (SplitOccured != 0)
{
// ~  Second deal with the INNER NODE(S) i.e Case #3 & Case #4:
        while (StackPtr != 0 || SplitOccured != 0)
              {
        // 'PseudoLinkedPointerNEW' is new LEAF to be inserted
        // 'wrdUP' is NEW word to be inserted
        if (StackPtr != 0)
        {
           POffsetInLEAF = BSTstack[--StackPtr];
           PseudoLinkedPointer = BSTstack[--StackPtr];
if ( *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) != 0 ) // If LEAF is full: Case #4
    { SplitOccured = 1;
                      memcpy( wrdUPold, wrdUP, wrdlen ); // LW up
                      PseudoLinkedPointerNEWold = PseudoLinkedPointerNEW;
            // ALlocate NEW LEAF:
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + 2*wrdlen + 4 + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] ) // +4 more for BST instead of LL; + more(see LEAF)
                      {
                      memcpy( &PseudoLinkedPointerNEW, &bufend[LetterOffset], 4 );
                      bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4 + 4; // + 4 due to above commenting
                      bufend[LetterOffset] = bufend[LetterOffset] + 2*wrdlen;
                      if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                      }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into B-trees order 3: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
      if (POffsetInLEAF == 0) // wrdUPold < LW
         {
                      memcpy( wrdUP, PseudoLinkedPointer+4+4+4, wrdlen ); // LW up
                      memcpy( PseudoLinkedPointer+4+4+4, wrdUPold, wrdlen );   // wrdUPold go to OLD LEAF
                      memcpy( PseudoLinkedPointerNEW+4+4+4, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW go to NEW LEAF
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
                      // [LP](PseudoLinkedPointerNEWold)[MP][RP](wrdUPold)[LW][RW]       ------
                      //              pair [LW] PseudoLinkedPointerNEW goes up                |
                      // PseudoLinkedPointer:                         PseudoLinkedPointerNEW: |
                      // [LP](PseudoLinkedPointerNEWold)[](wrdUPold)  [MP][RP][][RW]      <----
                      // no need to put zero in RP because logic is based on words existence:
                      memcpy( PseudoLinkedPointerNEW+0, PseudoLinkedPointer+4, 4 );  
                      memcpy( PseudoLinkedPointerNEW+4, PseudoLinkedPointer+8, 4 );  
                      memcpy( PseudoLinkedPointer+4, &PseudoLinkedPointerNEWold, 4 );
         }
      if (POffsetInLEAF == 4) // LW < wrdUPold < RW
         {
                      memcpy( wrdUP, wrdUPold, wrdlen );                       // wrdUPold up
                      memcpy( PseudoLinkedPointerNEW+4+4+4, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW go to NEW LEAF
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
                      // [LP][MP](PseudoLinkedPointerNEWold)[RP][LW](wrdUPold)[RW]       ------
                      //              pair [wrdUPold] PseudoLinkedPointerNEW goes up          |
                      // PseudoLinkedPointer:  PseudoLinkedPointerNEW:                        |
                      // [LP][MP][][LW]        (PseudoLinkedPointerNEWold)[RP][][RW]      <----
                      // no need to put zero in RP because logic is based on words existence:
                      memcpy( PseudoLinkedPointerNEW+0, &PseudoLinkedPointerNEWold, 4 );  
                      memcpy( PseudoLinkedPointerNEW+4, PseudoLinkedPointer+8, 4 );  
         }
      if (POffsetInLEAF == 8) // wrdUPold > RW
         {
                      memcpy( wrdUP, PseudoLinkedPointer+4+4+4+wrdlen, wrdlen ); // RW up
                      *(char *)(PseudoLinkedPointer+4+4+4+wrdlen) = 0;    // RW mark unused in OLD LEAF
                      memcpy( PseudoLinkedPointerNEW+4+4+4, wrdUPold, wrdlen );   // wrdUPold go to NEW LEAF
                      // [LP][MP][RP](PseudoLinkedPointerNEWold)[LW][RW](wrdUPold)       ------
                      //              pair [RW] PseudoLinkedPointerNEW goes up                |
                      // PseudoLinkedPointer:  PseudoLinkedPointerNEW:                        |
                      // [LP][MP][][LW]        [RP](PseudoLinkedPointerNEWold)[](wrdUPold) <---
                      // no need to put zero in RP because logic is based on words existence:
                      memcpy( PseudoLinkedPointerNEW+0, PseudoLinkedPointer+8, 4 );  
                      memcpy( PseudoLinkedPointerNEW+4, &PseudoLinkedPointerNEWold, 4 );
         }
    }
else // If LEAF is not full: Case #3
    { SplitOccured = 0; 
      if (POffsetInLEAF == 0) // wrdUP < [LW][] so [LW][] -> [][LW] -> [wrdUP][LW]
         {
                      memcpy( PseudoLinkedPointer+4+4+4+wrdlen, PseudoLinkedPointer+4+4+4, wrdlen );
                      memcpy( PseudoLinkedPointer+4+4+4, wrdUP, wrdlen );
                              // [LP][MP][] -> [LP][][MP] -> [LP][np][MP]
                      memcpy( PseudoLinkedPointer+8, PseudoLinkedPointer+4, 4 );  
                      memcpy( PseudoLinkedPointer+4, &PseudoLinkedPointerNEW, 4 );
         }
      if (POffsetInLEAF == 4) // wrdUP > [LW][] so [LW][] -> [LW][wrdUP]
         {
                      memcpy( PseudoLinkedPointer+4+4+4+wrdlen, wrdUP, wrdlen );
                              // [LP][MP][] -> [LP][MP][np]
                      memcpy( PseudoLinkedPointer+8, &PseudoLinkedPointerNEW, 4 );
         }
           break; 
    }
        }
        else // Empty stack means ROOT and more over ROOT is already splitted(Case #4 is off)
        {
     // If LEAF is not full: Case #3
     // THIS IS WHERE A NEW(SECOND) LEAF 'PseudoLinkedPointerROOT' must be allocated:
            if( (unsigned long)(bufend[LetterOffset] - BufStart) + 2*wrdlen + 4 + 4 + 4 < GRMBLFoolAgain[(int)wrdlen] ) // +4 more for BST instead of LL; + more(see LEAF)
                      {
                      memcpy( &PseudoLinkedPointerROOT, &bufend[LetterOffset], 4 );
                      bufend[LetterOffset] = bufend[LetterOffset] + 4 + 4 + 4; // + 4 due to above commenting
                      memcpy( bufend[LetterOffset], wrdUP, wrdlen ); 
                      bufend[LetterOffset] = bufend[LetterOffset] + 2*wrdlen;
                      if (MAXusedBuffer[wrdlen] < (unsigned long)(bufend[LetterOffset] - BufStart)) {MAXusedBuffer[wrdlen] = (unsigned long)(bufend[LetterOffset] - BufStart);}
                      }
            else
            { printf( "\nLeprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n" );
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into B-trees order 3: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
}
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
              fprintf( fp_outLOG, "Leprechaun: Failure! Increment 'Memory for each Letter' parameter(third one)!\n\n");
              return( 1 );
            }
            // Here                    --  'PseudoLinkedPointerROOT' --
            //                         |           (wrdUP)            |
            // 'PseudoLinkedPointer' <--                              --> 'PseudoLinkedPointerNEW'
            //         (LW)                                                          (RW)
            memcpy( PseudoLinkedPointerROOT, &PseudoLinkedPointer, 4 );      // LP
            memcpy( PseudoLinkedPointerROOT+4, &PseudoLinkedPointerNEW, 4 ); // MP
            // Here must NEW ROOT be updated i.e. HASH table(SLOT) must point it:
            memcpy( BufStart+Slot, &PseudoLinkedPointerROOT, 4 );
           break; //because it is ROOT without split
        }
              } // while
} //if (SplitOccured != 0)
// 3] Insert Iterative ]
} //if (FoundInLinkedList == 0)
// ########################################## B-tree order 3 ]
}
                        } // if( 1 <= wrdlen && wrdlen <= 31 )
			wrdlen = 0;
                        // This fragment is MIRRORed: #1 copy ]
                }
                //else if( workbyte >= 'A' &&  workbyte <= 'Z' )
                else if( workbyte <= 'Z' )
		{
                        if( wrdlen < 31 )
                        { wrd[ wrdlen ] = workbyte + 32 ; }
                        wrdlen++;
		}
                else if( workbyte >= 'a' &&  workbyte <= 'z' )
		{
                        if( wrdlen < 31 )
                        { wrd[ wrdlen ] = workbyte; }
                        wrdlen++;
		}
		else
                {
                        // This fragment is MIRRORed: #2 copy [
                goto ElStupido;
                        // This fragment is MIRRORed: #2 copy ]
		}
        } // i 'for'
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++Melnitchka;
Melnitchka = Melnitchka % 4;
if (Melnitchka == 0){ printf( "|; Word count: %s of them %s distinct; Done: %lu/64\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), 64 ); }
if (Melnitchka == 1){ printf( "/; Word count: %s of them %s distinct; Done: %lu/64\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), 64 ); }
if (Melnitchka == 2){ printf( "-; Word count: %s of them %s distinct; Done: %lu/64\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), 64 ); }
if (Melnitchka == 3){ printf( "\\; Word count: %s of them %s distinct; Done: %lu/64\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10), 64 ); }

        LINE10len = 0;
LINE10[ LINE10len ] = 0;
fclose( fp_inLINE );
                  }
                }
        } // k 'for'

(void) time(&t3);
if (t3 <= t1) {t3 = t1; t3++;}
printf( "Words per second performance: %sW/s\n", _ui64toaKAZEcomma(WORDcount/((int) t3-t1), llTOaDigits, 10) );  // Rev. 12+

        // FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH FLUSH
printf("Flushing unsorted words ...\n");
if( ( fp_out = fopen( argv[2], "wb+" ) ) == NULL )
{ printf( "Leprechaun: Can't create file %s \n", argv[2] ); return( 1 ); }
ZEROS[0] = 0; ZEROS[1] = 0; ZEROS[2] = 0; ZEROS[3] = 0;
CRdLFa[0] = 13; CRdLFa[1] = 10;

for( i = 0; i < 806; i++ )
{ //BufStart = pointerflush + i * LetterBuffer; // OLD
  BufStart = pointerflush + (i / 31) * WHOLEletter_BufferSize + OffsetsInBuffer[i % 31];
//  for( j = 0; j < NumberOfSLOTs; j++ )
//  { 
//                      Slot = j<<2;
//                      memcpy( &PseudoLinkedPointer, BufStart+Slot, 4 );
//                      while (PseudoLinkedPointer != 0)
//                      { memcpy( &PseudoLinkedPointerNEW, PseudoLinkedPointer, 4 );
//                        memcpy( PseudoLinkedPointer, ZEROS, 4 );
//                        PseudoLinkedPointer = PseudoLinkedPointerNEW;
//                      } 
//  }
//  // Start of COUPLES [OFFSET: 4byte(ZEROS)][WORD:up to 31bytes]
//  //fwrite(BufStart+(NumberOfSLOTs+1)*4, bufend[i] - (BufStart+(NumberOfSLOTs+1)*4), 1, fp_out );
//  /* Follows STATE OF UGLINESS: */
//  Flushing = BufStart+(NumberOfSLOTs+1)*4 + 4; // '+ 4' in order to skip first 4 zeros
//  //in case of current buffer not have been used then NOT entering in this cycle
//  while(Flushing < bufend[i])
//  { if (*Flushing != 0) {fwrite(Flushing, 1, 1, fp_out ); TotalWLchars++;}
//    // Below 'Flushing-1' works due to skipped first 4 zeros!
//    if (*(Flushing-1) != 0 && *Flushing == 0) {fwrite(CRdLFa, 2, 1, fp_out);}
//    //last word must be suffixed with 1310 too
//    if (Flushing == bufend[i]-1) {fwrite(CRdLFa, 2, 1, fp_out );}
//    Flushing++;
//  }

  for( j = 0; j < NumberOfSLOTs; j++ )
  { 
                      Slot = j<<2;
                      memcpy( &PseudoLinkedPointer, BufStart+Slot, 4 );
                      if (PseudoLinkedPointer != 0)
                      {
NumberOfTrees++;
if (BSTorBtree != 1)
{
// =========================================================== BST traverse [
     // DONE JOB:
     // Must be written BST traverse ! with simulated stack i.e. non-recursive.
     // ...
                                        // /*
                                        // Given a binary search tree, print out
                                        // its data elements in increasing
                                        // sorted order.
                                        // */
                                        // void printTree(struct node* node) {
                                        // if (node == NULL) return;
                                        // printTree(node->left);
                                        // printf("%d ", node->data);
                                        // printTree(node->right);
                                        // }

     // FUTURE JOB:
     // I need functions:
     //                  BST_LeafNumber() // greater the better
     //                  BST_NodeNumber() // 'BSTcurrent' below
     //                  BST_Peak()       // i.e. levels, root has height = 1
     //                  BST_PeakIB()     // IBBST(Ideal Balanced BST) has 1 + lgNodeNumber height
     // I need 'Ideal Balancing BST FRAGMENT' with simulated stack:
     // I need 'Ideal Balancing BST FRAGMENT' to be executed when Peak() >= PeakIB()<<1:

// ---------------------------------------------------------------------- [
  BSTcurrentNode = 0; BSTcurrentPeak = 0; BSTcurrentLeaf = 0;
                      BSTcurrentPeakMAX = 0; // Height of current BST
  StackPtr = 0;
  while ( 2==2 ) {
        while (PseudoLinkedPointer != 0)
              { 
                if (StackPtr > 65536*3-1-3) { printf( "\nLeprechaun: Failure! BST simulated stack overflow, too high BST!\n" ); return( 13 );}
                memcpy( &PseudoLinkedPointerNEWleft, PseudoLinkedPointer, 4 );
                PseudoLinkedPointer = PseudoLinkedPointer + 4;
                memcpy( &PseudoLinkedPointerNEWright, PseudoLinkedPointer, 4 );
                BSTstack[StackPtr] = PseudoLinkedPointer + 4; ++StackPtr; //ptr to wrd
                BSTstack[StackPtr] = PseudoLinkedPointerNEWright; ++StackPtr;
                BSTstack[StackPtr] = PseudoLinkedPointerNEWleft; ++StackPtr; //needed for stats not for recursion
        // BST stats [
                  if (PseudoLinkedPointerNEWleft == 0 && PseudoLinkedPointerNEWright == 0) {BSTcurrentLeaf++; BSTsTotalLEAFs++;}
                  BSTcurrentPeak++;
                  if (BSTcurrentPeakMAX < BSTcurrentPeak) BSTcurrentPeakMAX = BSTcurrentPeak;
                BSTstack[StackPtr] = BSTcurrentPeak; ++StackPtr; //needed for stats not for recursion
        // BST stats ]
                PseudoLinkedPointer = PseudoLinkedPointerNEWright; // choose right instead of 'PseudoLinkedPointerNEWleft' because of stats print
              }
        if (StackPtr == 0) break;
        BSTcurrentPeak = BSTstack[--StackPtr]; // level of the node(1 is root) needed only for stats(print)
        PseudoLinkedPointerNEWleft = BSTstack[--StackPtr]; // left pointer needed only for stats(print)
        PseudoLinkedPointerNEWright = BSTstack[--StackPtr]; // right pointer
        memcpy( wrd, BSTstack[--StackPtr], i%31+1 );
        fwrite(wrd, i%31+1, 1, fp_out); TotalWLchars = TotalWLchars + i%31+1;
        fwrite(CRdLFa, 2, 1, fp_out);
        BSTcurrentNode++;
        PseudoLinkedPointer = PseudoLinkedPointerNEWleft;
  }                                          
// ---------------------------------------------------------------------- ]
        // BST stats [
        if (BSTwithMAXnode < BSTcurrentNode) {
           BSTwithMAXnode = BSTcurrentNode;
           BSTwithMAXnodePEAK = BSTcurrentPeakMAX;
           BSTwithMAXnodeLEAF = BSTcurrentLeaf;
           BSTcurrentNodeMAXqUANTITY = 0;
        }
        if (BSTwithMAXnode == BSTcurrentNode) BSTcurrentNodeMAXqUANTITY++;
        if (BSTwithMAXpeak < BSTcurrentPeakMAX) {
           BSTwithMAXpeak = BSTcurrentPeakMAX;
           BSTwithMAXpeakNODE = BSTcurrentNode;
           BSTwithMAXpeakLEAF = BSTcurrentLeaf;
           BSTcurrentPeakMAXqUANTITY = 0;       iBSTwithMAXpeak=i; jBSTwithMAXpeak=j;
        }
        if (BSTwithMAXpeak == BSTcurrentPeakMAX) BSTcurrentPeakMAXqUANTITY++;
        if (BSTwithMAXleaf < BSTcurrentLeaf) {
           BSTwithMAXleaf = BSTcurrentLeaf;
           BSTwithMAXleafNODE = BSTcurrentNode;
           BSTwithMAXleafPEAK = BSTcurrentPeakMAX;
           BSTcurrentLeafMAXqUANTITY = 0; 
        }
        if (BSTwithMAXleaf == BSTcurrentLeaf) BSTcurrentLeafMAXqUANTITY++; 
        // BST stats ]
// =========================================================== BST traverse ]
} else
{
// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ B-tree order 3 traverse [
     // DONE JOB:
     // Must be written B-tree traverse ! with simulated stack i.e. non-recursive.
     // ...
  StackPtr = 0;
  while ( 2==2 ) {
        while (PseudoLinkedPointer != 0)
              { 
                if (StackPtr > 65536*3-1) { printf( "\nLeprechaun: Failure! B-tree simulated stack overflow, too high B-tree!\n" ); return( 13 );}
                BSTstack[StackPtr] = PseudoLinkedPointer; ++StackPtr; //ptr to Rwrd
if ( *(char *)(PseudoLinkedPointer + 4 + 4 + 4 + i%31+1) == 0 ) {memcpy( PseudoLinkedPointer + 4 + 4, &BufStart[NumberOfSLOTs*4], 4 );}
                memcpy( &PseudoLinkedPointerNEWleft, PseudoLinkedPointer, 4 );
                memcpy( &PseudoLinkedPointerNEWmiddle, PseudoLinkedPointer + 4, 4 );
                memcpy( &PseudoLinkedPointerNEWright, PseudoLinkedPointer + 4 + 4, 4 );
// Give first from right to left non-zero PTR
                if (PseudoLinkedPointerNEWright !=0 )
                { memcpy( PseudoLinkedPointer + 4 + 4, &BufStart[NumberOfSLOTs*4], 4 );
                  PseudoLinkedPointer = PseudoLinkedPointerNEWright;
                }
                else if (PseudoLinkedPointerNEWmiddle !=0 )
                { memcpy( PseudoLinkedPointer + 4, &BufStart[NumberOfSLOTs*4], 4 );
                  PseudoLinkedPointer = PseudoLinkedPointerNEWmiddle;
                }
                else if (PseudoLinkedPointerNEWleft !=0 )
                { memcpy( PseudoLinkedPointer, &BufStart[NumberOfSLOTs*4], 4 );
                  PseudoLinkedPointer = PseudoLinkedPointerNEWleft;
                }
                else
                {
                  PseudoLinkedPointer = 0;
                }
              }
        if (StackPtr == 0) break;
        PseudoLinkedPointer = BSTstack[--StackPtr];
                memcpy( &PseudoLinkedPointerNEWleft, PseudoLinkedPointer, 4 );
                memcpy( &PseudoLinkedPointerNEWmiddle, PseudoLinkedPointer + 4, 4 );
                memcpy( &PseudoLinkedPointerNEWright, PseudoLinkedPointer + 4 + 4, 4 );
        if (PseudoLinkedPointerNEWleft+PseudoLinkedPointerNEWmiddle+PseudoLinkedPointerNEWright == 0) // One LEAF is PRINTED when LP=0 MP=0 RP=0
           { 
        memcpy( wrd, PseudoLinkedPointer + 4 + 4 + 4, i%31+1 );
        fwrite(wrd, i%31+1, 1, fp_out); TotalWLchars = TotalWLchars + i%31+1;
        fwrite(CRdLFa, 2, 1, fp_out); 
        if ( *(char *)(PseudoLinkedPointer + 4 + 4 + 4 + i%31+1) != 0 )
             { memcpy( wrd, PseudoLinkedPointer + 4 + 4 + 4 + i%31+1, i%31+1 );
               fwrite(wrd, i%31+1, 1, fp_out); TotalWLchars = TotalWLchars + i%31+1;
               fwrite(CRdLFa, 2, 1, fp_out); 
             }
        PseudoLinkedPointer = 0;
           }
  }                                          
// $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ B-tree order 3 traverse ]
}
                      }
  } // j

} // i

if (BSTorBtree != 1)
{
// ~~~~~ Longest path ~~~~~ [
i=iBSTwithMAXpeak; j=jBSTwithMAXpeak;
  BufStart = pointerflush + (i / 31) * WHOLEletter_BufferSize + OffsetsInBuffer[i % 31];
                      Slot = j<<2;
                      memcpy( &PseudoLinkedPointer, BufStart+Slot, 4 );
                      if (PseudoLinkedPointer != 0)
                      {
// ---------------------------------------------------------------------- [
  BSTcurrentNode = 0; BSTcurrentPeak = 0; BSTcurrentLeaf = 0;
                      BSTcurrentPeakMAX = 0; // Height of current BST
  StackPtr = 0;
        // BST print [
                  fprintf( fp_outLOG, "A(not always THE) Binary-Search-Tree with the longest path(height, PEAK, number of levels):\n" );
        // BST print ]
  while ( 2==2 ) {
        while (PseudoLinkedPointer != 0)
              { 
                if (StackPtr > 65536*3-1-3) { printf( "\nLeprechaun: Failure! BST simulated stack overflow, too high BST!\n" ); return( 13 );}
                memcpy( &PseudoLinkedPointerNEWleft, PseudoLinkedPointer, 4 );
                PseudoLinkedPointer = PseudoLinkedPointer + 4;
                memcpy( &PseudoLinkedPointerNEWright, PseudoLinkedPointer, 4 );
                BSTstack[StackPtr] = PseudoLinkedPointer + 4; ++StackPtr; //ptr to wrd
                BSTstack[StackPtr] = PseudoLinkedPointerNEWright; ++StackPtr;
                BSTstack[StackPtr] = PseudoLinkedPointerNEWleft; ++StackPtr; //needed for stats not for recursion
        // BST stats [
                  if (PseudoLinkedPointerNEWleft == 0 && PseudoLinkedPointerNEWright == 0) {BSTcurrentLeaf++;} //BSTsTotalLEAFs++;} // REMOVED to avoid mess in TOTAL stats
                  BSTcurrentPeak++;
                  if (BSTcurrentPeakMAX < BSTcurrentPeak) BSTcurrentPeakMAX = BSTcurrentPeak;
                BSTstack[StackPtr] = BSTcurrentPeak; ++StackPtr; //needed for stats not for recursion
        // BST stats ]
                PseudoLinkedPointer = PseudoLinkedPointerNEWright; // choose right instead of 'PseudoLinkedPointerNEWleft' because of stats print
              }
        if (StackPtr == 0) break;
        BSTcurrentPeak = BSTstack[--StackPtr]; // level of the node(1 is root) needed only for stats(print)
        PseudoLinkedPointerNEWleft = BSTstack[--StackPtr]; // left pointer needed only for stats(print)
        PseudoLinkedPointerNEWright = BSTstack[--StackPtr]; // right pointer
        memcpy( wrd, BSTstack[--StackPtr], i%31+1 );
        //fwrite(wrd, i%31+1, 1, fp_out); TotalWLchars = TotalWLchars + i%31+1;
        //fwrite(CRdLFa, 2, 1, fp_out);
        BSTcurrentNode++;
        PseudoLinkedPointer = PseudoLinkedPointerNEWleft;
        // BST print [
                  for( k = 0; k < BSTcurrentPeak; k++ ) fprintf( fp_outLOG, "%c", ' ' );
                     if (PseudoLinkedPointerNEWleft == 0) fprintf( fp_outLOG, "[" ); else fprintf( fp_outLOG, "]" ); 
                  for( k = 0; k < i%31+1; k++ ) fprintf( fp_outLOG, "%c", *(char *)(wrd+k) );
                     if (PseudoLinkedPointerNEWright == 0) fprintf( fp_outLOG, "]" ); else fprintf( fp_outLOG, "[" );
                     if (BSTcurrentPeak == 1) fprintf( fp_outLOG, " ROOT" );
                     fprintf( fp_outLOG, "\n" );
        // BST print ]
  }                                          
// ---------------------------------------------------------------------- ]
                      }
fprintf( fp_outLOG, "Above Binary-Search-Tree with MaxPEAK = %s has NODEs = %s and LEAFs = %s\n", _ui64toaKAZEcomma(BSTwithMAXpeak, llTOaDigits2, 10), _ui64toaKAZEcomma(BSTwithMAXpeakNODE, llTOaDigits3, 10), _ui64toaKAZEcomma(BSTwithMAXpeakLEAF, llTOaDigits, 10));
                  fprintf( fp_outLOG, "Legend:\n" );
                  fprintf( fp_outLOG, "At left side of the word - '[' means no left successor\n" );
                  fprintf( fp_outLOG, "At left side of the word - ']' means left successor exists\n" );
                  fprintf( fp_outLOG, "At right side of the word - ']' means no right successor\n" );
                  fprintf( fp_outLOG, "At right side of the word - '[' means right successor exists\n" );
// ~~~~~ Longest path ~~~~~ ]

        // BST stats [
PEAKibBST=1+floorLog2(BSTwithMAXnode);
//PEAKibBST=1;
//while (BSTwithMAXnode>>PEAKibBST) PEAKibBST++;
        // BST stats ]
}

(void) time(&t2);
if (t2 <= t1) {t2 = t1; t2++;}
printf("Time for making unsorted wordlist: %d second(s)\n", (int) t2-t1);
fprintf( fp_outLOG, "Bytes per second performance: %sB/s\n", _ui64toaKAZEcomma(FilesLEN/((int) t3-t1), llTOaDigits, 10) );  // Rev. 12+
fprintf( fp_outLOG, "Words per second performance: %sW/s\n", _ui64toaKAZEcomma(WORDcount/((int) t3-t1), llTOaDigits, 10) );  // Rev. 12+
fprintf( fp_outLOG, "Input File with a list of TEXTual Files: %s\n", argv[1] );
fprintf( fp_outLOG, "Size of all TEXTual Files: %s\n", _ui64toaKAZEcomma(FilesLEN, llTOaDigits, 10) );
fprintf( fp_outLOG, "Word count: %s of them %s distinct\n", _ui64toaKAZEcomma(WORDcount, llTOaDigits, 10), _ui64toaKAZEcomma((unsigned long long)WORDcountDistinct, llTOaDigits2, 10) );
fprintf( fp_outLOG, "Number Of Files: %lu\n", NumberOfFiles );
fprintf( fp_outLOG, "Number Of Lines: %lu\n", NumberOfLines );
fprintf( fp_outLOG, "Allocated memory in MB: %lu\n", (unsigned long)(memory_size>>20)+1 );
NumberOfHashCollisions = WORDcountDistinct - NumberOfTrees;
fprintf( fp_outLOG, "Number Of Trees(GREATER THE BETTER): %lu\n", NumberOfTrees );
fprintf( fp_outLOG, "Forest population(Hash Function Quality regarding Collisions i.e. Hash Table Utilization): %lu%s\n", (NumberOfTrees*100)/(26*31*8192), "%\0" );
fprintf( fp_outLOG, "Number Of Hash Collisions(Distinct WORDs - Number Of Trees): %lu\n", NumberOfHashCollisions );

if (BSTorBtree != 1)
{
fprintf( fp_outLOG, "Maximum Attempts to Find/Put a WORD into a Binary-Search-Tree: '%s'\n", _ui64toaKAZEcomma(BSTwithMAXpeak, llTOaDigits, 10) );
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into Binary-Search-Trees: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
fprintf( fp_outLOG, "Total Number of LEAFs in Binary-Search-Trees(GREATER THE BETTER): %s\n", _ui64toaKAZEcomma(BSTsTotalLEAFs, llTOaDigits, 10) );
fprintf( fp_outLOG, "Perfectly-Balanced-Binary-Search-Tree for MaxNODEs = %s must have PEAK = %s = rounding down of integer (1+lb(%s))\n", _ui64toaKAZEcomma(BSTwithMAXnode, llTOaDigits, 10), _ui64toaKAZEcomma(PEAKibBST, llTOaDigits2, 10), _ui64toaKAZEcomma(BSTwithMAXnode, llTOaDigits3, 10));
fprintf( fp_outLOG, "Binary-Search-Tree(1st out of %s) with MaxNODEs = %s has PEAK = %s and LEAFs = %s\n", _ui64toaKAZEcomma(BSTcurrentNodeMAXqUANTITY, llTOaDigits4, 10), _ui64toaKAZEcomma(BSTwithMAXnode, llTOaDigits2, 10), _ui64toaKAZEcomma(BSTwithMAXnodePEAK, llTOaDigits3, 10), _ui64toaKAZEcomma(BSTwithMAXnodeLEAF, llTOaDigits, 10));
fprintf( fp_outLOG, "Binary-Search-Tree(1st out of %s) with MaxPEAK = '%s' has NODEs = %s and LEAFs = %s\n", _ui64toaKAZEcomma(BSTcurrentPeakMAXqUANTITY, llTOaDigits4, 10), _ui64toaKAZEcomma(BSTwithMAXpeak, llTOaDigits2, 10), _ui64toaKAZEcomma(BSTwithMAXpeakNODE, llTOaDigits3, 10), _ui64toaKAZEcomma(BSTwithMAXpeakLEAF, llTOaDigits, 10));
fprintf( fp_outLOG, "Binary-Search-Tree(1st out of %s) with MaxLEAFs = %s has NODEs = %s and PEAK = %s\n", _ui64toaKAZEcomma(BSTcurrentLeafMAXqUANTITY, llTOaDigits4, 10), _ui64toaKAZEcomma(BSTwithMAXleaf, llTOaDigits2, 10), _ui64toaKAZEcomma(BSTwithMAXleafNODE, llTOaDigits3, 10), _ui64toaKAZEcomma(BSTwithMAXleafPEAK, llTOaDigits, 10));
} else
{
fprintf( fp_outLOG, "Total Attempts to Find/Put WORDs into B-trees order 3: %s\n", _ui64toaKAZEcomma(WORDcountAttemptsToPut, llTOaDigits, 10) );
}

for( k = 1; k < 32; k++ )
{ fprintf( fp_outLOG, "Words with length %s occupy %sKB of %sKB given i.e. %s%s utilization\n", _ui64toaKAZEzerocomma(k, llTOaDigits, 10)+(26-2), _ui64toaKAZEzerocomma((MAXusedBuffer[k]>>10)+1, llTOaDigits2, 10)+(26-5), _ui64toaKAZEzerocomma((((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1, llTOaDigits3, 10)+(26-5), _ui64toaKAZEzerocomma((unsigned long long)(MAXusedBuffer[k]*100)/((GRMBLhill[(int)k] * LetterBuffer)/31), llTOaDigits4, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
  if ( MAXusedBufferABS < (31 * ((MAXusedBuffer[k]>>10)+1)) / GRMBLhill[(int)k] ) {MAXusedBufferABS = 1+(31 * ((MAXusedBuffer[k]>>10)+1)) / GRMBLhill[(int)k];}
  Utiliza1 = Utiliza1 + (MAXusedBuffer[k]>>10)+1;
  Utiliza2 = Utiliza2 + (((GRMBLhill[(int)k] * LetterBuffer)/31)>>10)+1;
}
fprintf( fp_outLOG, "Total pseudo(including hash table) memory utilization: %s%s\n", _ui64toaKAZEzerocomma((Utiliza1*100)/Utiliza2, llTOaDigits, 10)+(26-2), "%\0" ); // 26 are all 26-DESIRED=24
fprintf( fp_outLOG, "Total real(wordlist's words VS allocated block) memory utilization: %s/1000\n", _i64toaKAZE(((unsigned long long)TotalWLchars*1000)/memory_size, llTOaDigits, 10) ); // 26 are all 26-DESIRED=24
fprintf( fp_outLOG, "Used value for third parameter in KB: %lu\n", (unsigned long)Thunderwith );
fprintf( fp_outLOG, "Use next time as third parameter: %lu-\n", MAXusedBufferABS ); // 26 are all 26-DESIRED=24
fprintf( fp_outLOG, "Time for making unsorted wordlist: %d second(s)\n", (int) t2-t1);

// EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT EXIT
printf( "Deallocated memory in MB: %lu\n", (memory_size>>20)+1 );
free(pointerflush);
fclose(fp_out);
fclose(fp_outLOG);
// SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT
   //printf("Uploading unsorted wordlist ...\n");
   if ((nlines = readlines(argv[2], &backup)) >= 0)
   {  //printf("Number of words(lines) uploaded: %lu\n", nlines);
      //printf("Note1: Press 'Ctrl+C' to abort sorting, unsorted wordlist(second parameter)\n");
      //printf("       will remain intact(unless flushing is in progress) because of\n");
      //printf("       pointers-to-data are being sorted not the data itself.\n");
      //printf("Note2: In near future 'InsertionX26Sort' will be replaced with 'QuickX26Sort':\n");
      //printf("       which is much faster than 'QuickSort' applied for data-at-once!\n");

      // !!!??? I AM DISAPPOINTED x26 is just an illusion !!!???
      // X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26
// argc is 4|5|6 due to eventual missing BufferSize
if( argc == 4 ) // not 5 due to eventual missing BufferSize
    k = 3;
if( argc == 5 || argc == 6 )  
    k = 4;
if (*argv[k] != 'A' && *argv[k] != 'a' && *argv[k] != 'B' && *argv[k] != 'b' && *argv[k] != 'C' && *argv[k] != 'c' && *argv[k] != 'D' && *argv[k] != 'd')
{ printf("Sorting(with 'MultiKeyQuickSortX26Sort' by J. Bentley and R. Sedgewick) ...\n");
      /* ???!!! What an unexpected behavior! I have been hit: for SOED5.HTM(259,835 distinct words): InsertionX26Sort gives 46s, InsertionSort gives 28s */
      for( k = 0; k < 26; k++ )
      { printf( "Sort pass %s/26 ...\r", _ui64toaKAZEzerocomma(k+1, llTOaDigits, 10)+(26-2));
        HEADOffetFromStartBUKVA = TAILOffetFromStartBUKVA;
        while( (TAILOffetFromStartBUKVA < nlines) && (*backup[TAILOffetFromStartBUKVA] - 'a' == k) )
        { TAILOffetFromStartBUKVA++;
        }
        if (HEADOffetFromStartBUKVA != TAILOffetFromStartBUKVA)
        { mkqsort_main(backup + HEADOffetFromStartBUKVA, TAILOffetFromStartBUKVA - HEADOffetFromStartBUKVA + 0); // backup[0..nlines-1]
        }
      }
}
else
{
if (*argv[k] == 'A' || *argv[k] == 'a')
   { printf("Sorting(with 'InsertionSort') ...");
     InsertSortKAZE(backup, nlines, 0); // backup[0..nlines-1]
   }
if (*argv[k] == 'B' || *argv[k] == 'b')
   { printf("Sorting(with 'InsertionX26Sort') ...\n");
      /* ???!!! What an unexpected behavior! I have been hit: for SOED5.HTM(259,835 distinct words): InsertionX26Sort gives 46s, InsertionSort gives 28s */
      for( k = 0; k < 26; k++ )
      { printf( "Sort pass %s/26 ...\r", _ui64toaKAZEzerocomma(k+1, llTOaDigits, 10)+(26-2));
        HEADOffetFromStartBUKVA = TAILOffetFromStartBUKVA;
        while( (TAILOffetFromStartBUKVA < nlines) && (*backup[TAILOffetFromStartBUKVA] - 'a' == k) )
        { TAILOffetFromStartBUKVA++;
        }
        if (HEADOffetFromStartBUKVA != TAILOffetFromStartBUKVA)
        { InsertSortKAZE(backup + HEADOffetFromStartBUKVA, TAILOffetFromStartBUKVA - HEADOffetFromStartBUKVA + 0, 0); // backup[0..nlines-1]
        }
      }
   }
if (*argv[k] == 'C' || *argv[k] == 'c')
   { printf("Sorting(with 'MultiKeyQuickSortSort' by J. Bentley and R. Sedgewick) ...");
     mkqsort_main(backup, nlines); // backup[0..nlines-1]
   }
if (*argv[k] == 'D' || *argv[k] == 'd')
   { printf("Sorting(with 'MultiKeyQuickSortX26Sort' by J. Bentley and R. Sedgewick) ...\n");
      /* ???!!! What an unexpected behavior! I have been hit: for SOED5.HTM(259,835 distinct words): InsertionX26Sort gives 46s, InsertionSort gives 28s */
      for( k = 0; k < 26; k++ )
      { printf( "Sort pass %s/26 ...\r", _ui64toaKAZEzerocomma(k+1, llTOaDigits, 10)+(26-2));
        HEADOffetFromStartBUKVA = TAILOffetFromStartBUKVA;
        while( (TAILOffetFromStartBUKVA < nlines) && (*backup[TAILOffetFromStartBUKVA] - 'a' == k) )
        { TAILOffetFromStartBUKVA++;
        }
        if (HEADOffetFromStartBUKVA != TAILOffetFromStartBUKVA)
        { mkqsort_main(backup + HEADOffetFromStartBUKVA, TAILOffetFromStartBUKVA - HEADOffetFromStartBUKVA + 0); // backup[0..nlines-1]
        }
      }
   }
}
      // X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26 X26

      printf("\nFlushing sorted words ...\n");
      if( ( fp_out = fopen( argv[2], "wb+" ) ) == NULL )
      { printf( "Leprechaun: Can't create file %s \n", argv[2] ); return( 1 ); }
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
        fprintf(fp_out, "%s", backup[j]);
        fwrite(CRdLFa, 2, 1, fp_out );
      }
      (void) time(&t3);
      if (t3 <= t2) {t3 = t2; t3++;}
      printf("Time for sorting unsorted wordlist: %d second(s)\n", (int) t3-t2);


/*
// Hash benchmarking ---------------------------------------------- [

// 1[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
// To make it EVEN !!!
//wrdlen = strlen(backup[j]);
//if (strlen(backup[j]) != 0)
              Slot = FNV1A_Hash(backup[j]); //13+++
      }
}
clocks2 = clock();
printf( "Performance of 'FNV1A_Hash': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 1]

// 3[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
// To make it EVEN !!!
//wrdlen = strlen(backup[j]);
//if (strlen(backup[j]) != 0)
              Slot = FNV1A_Hash_SHIFTless_XORless(backup[j]); //13+++
      }
}
clocks2 = clock();
printf( "Performance of 'FNV1A_Hash_SHIFTless_XORless': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 3]

// 5[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
              Slot = FNV1A_Hash_4_OCTETS(backup[j], (strlen(backup[j])>>2)); //13+++
      }
}
clocks2 = clock();
printf( "Performance of 'FNV1A_Hash_4_OCTETS': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 5]

// 2[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
              Slot = FNV1A_Hash_4_OCTETS_31(backup[j], (strlen(backup[j])>>2)); //13+++
      }
}
clocks2 = clock();
printf( "Performance of 'FNV1A_Hash_4_OCTETS_31': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 2]

// 4[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
// To make it EVEN !!!
//wrdlen = strlen(backup[j]);
//if (strlen(backup[j]) != 0)
              Slot = KuxHash3plus(backup[j]); //13++
      }
}
clocks2 = clock();
printf( "Performance of 'KuxHash3plus': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 4]

// 6[
clocks1 = clock();
    for (Bozan=0; Bozan < (1<<4); Bozan++) // 16 times, at end >>4
{
      for( j = 0; j < nlines; j++ )
      { //Slot = KuxHash3plus(backup[j]);
        //fprintf(fp_out, "Hashcode: %s - ", _ui64toaKAZEzerocomma(Slot, llTOaDigits, 10)+(26-5));
wrdlen = strlen(backup[j]);
if (wrdlen<=19) // 4x4+3=19 i.e. last contains 7 clashes
              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>2, 2); //13+++++
else            // 2x8+4=20 i.e. first contains 6 clashes
              Slot = FNV1A_Hash_Granularity(wrd, wrdlen>>3, 3)2; //13+++++
      } // Conclusion: two functions > 64 bytes lead to horrible slowness, so unite them in one: fit in the cache line.
}
clocks2 = clock();
printf( "Performance of 'FNV1A_Hash_Granularity': %lu words/clock or %lu MB/s\n", (nlines/((long)(clocks2 - clocks1 + 1)>>4)) , ((TotalWLchars>>10)/((long)(clocks2 - clocks1 + 1)>>4))  );
// 6]

// Hash benchmarking ---------------------------------------------- ]
*/


if( ( fp_outLOG = fopen( "Leprechaun.LOG", "a+" ) ) == NULL )
{ printf( "Leprechaun: Can't open file Leprechaun.LOG.\n" ); return( 1 ); }
fprintf( fp_outLOG, "Time for sorting unsorted wordlist: %d second(s)\n\n", (int) t3-t2);
printf( "Leprechaun: Done.\n" );
      return 0;
   } 
   else 
   {  printf("Leprechaun: Input file too large, wordlist remains unsorted!\n");
      return 1;
   }
// SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT SORT
}

/*
TO BE DONE: Ideal Balancing BST [

link rotR(link h)
  { link x = h->l; h->l = x->r; x->r = h; 
    return x; }

link rotL(link h)
  { link x = h->r; h->r = x->l; x->l = h; 
    return x; }

link partR(link h, int k)
  { int t = h->l->N; 
    if (t > k )
      { h->l = partR(h->l, k); h = rotR(h); }
    if (t < k )
      { h->r = partR(h->r, k-t-1); h = rotL(h); }
    return h;
  }

link balanceR(link h)
  { 
    if (h->N < 2) return h;
    h = partR(h, h->N/2);
    h->l = balanceR(h->l); 
    h->r = balanceR(h->r);
    return h;
  }

TO BE DONE: Ideal Balancing BST ]
*/

/*
#include <stdlib.h>
#include "Item.h"
typedef struct STnode* link;
struct STnode { Item item; link l, r; int N };
static link head, z;
link NEW(Item item, link l, link r, int N)
  { link x = malloc(sizeof *x); 
    x->item = item; x->l = l; x->r = r; x->N = N;
    return x;
  }
void STinit()
  { head = (z = NEW(NULLitem, 0, 0, 0)); }
int STcount() { return head->N; }
Item searchR(link h, Key v)
  { Key t = key(h->item);
    if (h == z) return NULLitem;
    if eq(v, t) return h->item;
    if less(v, t) return searchR(h->l, v);
             else return searchR(h->r, v);
  }
Item STsearch(Key v) 
  { return searchR(head, v); } 
link insertR(link h, Item item)
  { Key v = key(item), t = key(h->item);
    if (h == z) return NEW(item, z, z, 1);
    if less(v, t) 
         h->l = insertR(h->l, item);
    else h->r = insertR(h->r, item);
    (h->N)++; return h;
  }
void STinsert(Item item)
  { head = insertR(head, item); }
*/

/*
int count(link h)
  { 
    if (h == NULL) return 0;
    return count(h->l) + count(h->r) + 1;
  }

int height(link h)
  { int u, v;
    if (h == NULL) return -1;
    u = height(h->l); v = height(h->r);
    if (u > v) return u+1; else return v+1;
  }

void printnode(char c, int h)
  { int i;
    for (i = 0; i < h; i++) printf("  ");
    printf("%c\n", c);
  }

void show(link x, int h)
  { 
    if (x == NULL) { printnode("*", h); return; }
    show(x->r, h+1);    
    printnode(x->item, h);
    show(x->l, h+1);    
  }
*/
