diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index a1de19b..211d311 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -16,14 +16,16 @@ jobs:
     name: Linux test (remote)
     runs-on: ubuntu-latest
     env: 
-      EXE: ./bin/kmc      
-      KMC_SINGLE_READ: ./tests/kmc_CLI/data/single_read.fq      
-    
+      EXE: ./bin/kmc
+      EXE_DUMP: ./bin/kmc_dump
+      KMC_SINGLE_READ: ./tests/kmc_CLI/data/single_read.fq
+      DATA_DIR: ./tests/kmc_CLI/data/
     steps:
     - uses: actions/checkout@v2
     - name: make
-      run: make -j12 kmc
-    
+      run: |
+        g++ -v
+        make -j12 kmc kmc_tools kmc_dump
 
     - name: KMC single read, k=28, ci=1
       run: |
@@ -38,6 +40,11 @@ jobs:
       run: |
         $EXE -k10 -v  $KMC_SINGLE_READ 10mers .
         $EXE -k9 -v -fkmc 10mers 9mers .
+    - name: issue 180
+      run: |
+        $EXE -v -k5 -fa -ci1 -t1 $DATA_DIR/issue-180/input.fa bug-report.kmc .
+        $EXE_DUMP bug-report.kmc issue-180.kmers
+        cmp issue-180.kmers $DATA_DIR/issue-180/pattern.dump
         
   macos-remote:
     name: macOS build (remote)
diff --git a/.github/workflows/self-hosted.yml b/.github/workflows/self-hosted.yml
new file mode 100644
index 0000000..5de36ea
--- /dev/null
+++ b/.github/workflows/self-hosted.yml
@@ -0,0 +1,76 @@
+name: Self-hosted CI
+on:
+  pull_request:
+    branches: [ master ]
+    paths-ignore:
+      - '**.md'
+  workflow_dispatch:
+
+jobs:
+  check-prerequisites:
+    name: Check prerequisites
+    runs-on: [self-hosted, kmc]
+    env:
+      DATA_DIR: ../../../../data
+      SCRIPT: tests/kmc_CLI/check-prerequisites.py
+    steps:
+    - name: Check prerequisites
+      run: |
+        chmod +x $SCRIPT
+        /usr/bin/time -v $SCRIPT $DATA_DIR
+
+  prepare-small-fastq-tests:
+    name: Prepare small fastq tests
+    runs-on: [self-hosted, kmc]
+    env:      
+      TRIVIAL_COUNTER: tests/kmc_CLI/trivial-k-mer-counter/bin/counter
+      DATA_DIR: ../../../../data
+      SCRIPT: tests/kmc_CLI/prepare_small_fastq_tests.py
+      FILE_TO_GET_PART_FROM: F.vesca/SRR072005.fastq.gz
+    steps:      
+    - name: Compile trivial counter
+      run: |
+        (cd tests/kmc_CLI/trivial-k-mer-counter; /usr/bin/time -v make)
+    - name: Prepare pattern data
+      run: |
+        chmod +x $SCRIPT
+        /usr/bin/time -v $SCRIPT $DATA_DIR $TRIVIAL_COUNTER $FILE_TO_GET_PART_FROM 400000
+
+  make-tests:
+    name: Make tests
+    runs-on: [self-hosted, kmc]
+    needs: check-prerequisites
+    env: 
+      KMC_EXE: ./bin/kmc
+      KMC_DUMP_EXE: ./bin/kmc_dump
+      KMC_TOOLS: ./bin/kmc_tools
+    steps:
+    - uses: actions/checkout@v2
+    - name: make (default)
+      run: |
+        /usr/bin/time -v make -j32
+
+  small-fastq-tests:
+    name: Small fastq tests
+    runs-on: [self-hosted, kmc]
+    needs: [make-tests, prepare-small-fastq-tests]
+    env:      
+      DATA_DIR: ../../../../data
+      SCRIPT: tests/kmc_CLI/run_small_fastq_tests.py
+      KMC_EXE: ./bin/kmc
+      KMC_DUMP_EXE: ./bin/kmc_dump
+      KMC_TOOLS: ./bin/kmc_tools
+
+    steps:
+    - name: Run all small fastq tests
+      run: |
+        chmod +x $SCRIPT
+        /usr/bin/time -v $SCRIPT $DATA_DIR $KMC_EXE $KMC_TOOLS $KMC_DUMP_EXE
+   
+
+
+
+
+
+
+  
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
index 740cd88..f9224a4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+kmc (3.2.1+git20220114.1.a68b0c9-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 28 Mar 2022 18:00:38 -0000
+
 kmc (3.2.1+dfsg-1) unstable; urgency=medium
 
   * New upstream version
diff --git a/debian/patches/0005-Add-static-library-target-to-makefile.patch b/debian/patches/0005-Add-static-library-target-to-makefile.patch
index 139230d..e98b0dc 100644
--- a/debian/patches/0005-Add-static-library-target-to-makefile.patch
+++ b/debian/patches/0005-Add-static-library-target-to-makefile.patch
@@ -5,6 +5,8 @@ From: Kevin Murray <spam@kdmurray.id.au>
  makefile | 13 ++++++++++---
  1 file changed, 10 insertions(+), 3 deletions(-)
 
+Index: kmc/Makefile
+===================================================================
 --- kmc.orig/Makefile
 +++ kmc/Makefile
 @@ -1,4 +1,4 @@
@@ -13,7 +15,7 @@ From: Kevin Murray <spam@kdmurray.id.au>
  
  UNAME_S := $(shell uname -s)
  
-@@ -131,6 +131,10 @@
+@@ -131,6 +131,10 @@ py_kmc_api: $(PY_KMC_API_OBJS) $(PY_KMC_
  	-o $(OUT_BIN_DIR)/$@`python3-config --extension-suffix` \
  	$(LDFLAGS)
  
@@ -24,7 +26,7 @@ From: Kevin Murray <spam@kdmurray.id.au>
  clean:
  	-rm -f $(KMC_MAIN_DIR)/*.o
  	-rm -f $(KMC_API_DIR)/*.o
-@@ -140,3 +144,4 @@
+@@ -140,3 +144,4 @@ clean:
  	-rm -f $(PY_KMC_API_DIR)/*.so
  	-rm -rf $(OUT_BIN_DIR)
  	-rm -rf $(OUT_INCLUDE_DIR)
diff --git a/debian/patches/disable-python-bindings.patch b/debian/patches/disable-python-bindings.patch
index 306f4f1..0c5e979 100644
--- a/debian/patches/disable-python-bindings.patch
+++ b/debian/patches/disable-python-bindings.patch
@@ -6,6 +6,8 @@ Forwarded: not-needed
 Last-Update: 2020-12-10
 ---
 This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: kmc/Makefile
+===================================================================
 --- kmc.orig/Makefile
 +++ kmc/Makefile
 @@ -1,4 +1,4 @@
diff --git a/debian/patches/makefile.patch b/debian/patches/makefile.patch
index 00efaf7..d277101 100644
--- a/debian/patches/makefile.patch
+++ b/debian/patches/makefile.patch
@@ -5,9 +5,11 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  makefile | 10 +++++-----
  1 file changed, 5 insertions(+), 5 deletions(-)
 
+Index: kmc/Makefile
+===================================================================
 --- kmc.orig/Makefile
 +++ kmc/Makefile
-@@ -20,12 +20,10 @@
+@@ -20,12 +20,10 @@ ifeq ($(UNAME_S),Darwin)
  
  	PY_KMC_API_CFLAGS = -Wl,-undefined,dynamic_lookup -fPIC -Wall -shared -std=c++14 -O3
  else
@@ -24,7 +26,7 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  endif
  
  KMC_CLI_OBJS = \
-@@ -92,16 +90,16 @@
+@@ -92,16 +90,16 @@ $(KMC_TOOLS_DIR)/kff_info_reader.o
  
  
  $(KMC_CLI_OBJS) $(KMC_CORE_OBJS) $(KMC_DUMP_OBJS) $(KMC_API_OBJS) $(KFF_OBJS) $(KMC_TOOLS_OBJS): %.o: %.cpp
@@ -46,7 +48,7 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  
  $(LIB_KMC_CORE): $(KMC_CORE_OBJS) $(RADULS_OBJS) $(KMC_API_OBJS) $(KFF_OBJS)
  	-mkdir -p $(OUT_INCLUDE_DIR)
-@@ -111,26 +109,27 @@
+@@ -111,26 +109,27 @@ $(LIB_KMC_CORE): $(KMC_CORE_OBJS) $(RADU
  
  kmc: $(KMC_CLI_OBJS) $(LIB_KMC_CORE)
  	-mkdir -p $(OUT_BIN_DIR)
diff --git a/debian/patches/simde b/debian/patches/simde
index 1d8b2cc..7b78279 100644
--- a/debian/patches/simde
+++ b/debian/patches/simde
@@ -1,8 +1,10 @@
 Author: Michael R. Crusoe <crusoe@debian.org>
 Description: support non-x86 systems via libsimde-dev
+Index: kmc/Makefile
+===================================================================
 --- kmc.orig/Makefile
 +++ kmc/Makefile
-@@ -53,11 +53,16 @@
+@@ -53,11 +53,16 @@ ifeq ($(UNAME_S),Darwin)
  
  	LIB_KMC_CORE = $(OUT_BIN_DIR)/libkmc_core.mac.a
  else
@@ -19,7 +21,7 @@ Description: support non-x86 systems via libsimde-dev
  
  	LIB_KMC_CORE = $(OUT_BIN_DIR)/libkmc_core.a
  endif
-@@ -92,6 +97,7 @@
+@@ -92,6 +97,7 @@ $(KMC_TOOLS_DIR)/kff_info_reader.o
  $(KMC_CLI_OBJS) $(KMC_CORE_OBJS) $(KMC_DUMP_OBJS) $(KMC_API_OBJS) $(KFF_OBJS) $(KMC_TOOLS_OBJS): %.o: %.cpp
  	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
  
@@ -27,7 +29,7 @@ Description: support non-x86 systems via libsimde-dev
  $(KMC_MAIN_DIR)/raduls_sse2.o: $(KMC_MAIN_DIR)/raduls_sse2.cpp
  	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -msse2 -c $< -o $@
  $(KMC_MAIN_DIR)/raduls_sse41.o: $(KMC_MAIN_DIR)/raduls_sse41.cpp
-@@ -100,6 +106,10 @@
+@@ -100,6 +106,10 @@ $(KMC_MAIN_DIR)/raduls_avx.o: $(KMC_MAIN
  	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -mavx -c $< -o $@
  $(KMC_MAIN_DIR)/raduls_avx2.o: $(KMC_MAIN_DIR)/raduls_avx2.cpp
  	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -mavx2 -c $< -o $@
@@ -38,9 +40,11 @@ Description: support non-x86 systems via libsimde-dev
  
  $(LIB_KMC_CORE): $(KMC_CORE_OBJS) $(RADULS_OBJS) $(KMC_API_OBJS) $(KFF_OBJS)
  	-mkdir -p $(OUT_INCLUDE_DIR)
+Index: kmc/kmc_core/cpu_info.cpp
+===================================================================
 --- kmc.orig/kmc_core/cpu_info.cpp
 +++ kmc/kmc_core/cpu_info.cpp
-@@ -37,6 +37,7 @@
+@@ -37,6 +37,7 @@ static struct CpuInfoImpl {
  	string vendor, brand;
  	void cpuid(int *result, int function_id) const
  	{
@@ -48,7 +52,7 @@ Description: support non-x86 systems via libsimde-dev
  #ifdef _MSC_VER
  		__cpuidex(result, function_id, 0);
  
-@@ -52,10 +53,12 @@
+@@ -52,10 +53,12 @@ static struct CpuInfoImpl {
  		__asm__("cpuid\n\t"
  			: "=a" (result[0]), "=b" (result[1]), "=c" (result[2]), "=d" (result[3]) : "0" (function_id), "c"(0));
  #endif  
@@ -61,7 +65,7 @@ Description: support non-x86 systems via libsimde-dev
  		array<int, 4> cpui = { -1 };
  		cpuid(cpui.data(), 0);
  		int nIds_ = cpui[0];
-@@ -89,6 +92,9 @@
+@@ -89,6 +92,9 @@ static struct CpuInfoImpl {
  			std::bitset<32> EBX = data_[7][1];
  			avx2 = EBX[5];
  		}
@@ -71,13 +75,15 @@ Description: support non-x86 systems via libsimde-dev
  	}
  
  	const string& GetVendor() const
-@@ -144,4 +150,4 @@
+@@ -144,4 +150,4 @@ bool CCpuInfo::SSE42_Enabled() { return
  bool CCpuInfo::AVX_Enabled() { return cpu_info_impl.avx; }
  bool CCpuInfo::AVX2_Enabled() { return cpu_info_impl.avx2; }
  
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/kmc_core/intr_copy.h
+===================================================================
 --- kmc.orig/kmc_core/intr_copy.h
 +++ kmc/kmc_core/intr_copy.h
 @@ -15,8 +15,8 @@
@@ -91,7 +97,7 @@ Description: support non-x86 systems via libsimde-dev
  #include "critical_error_handler.h"
  
  #ifndef _WIN32
-@@ -32,7 +32,7 @@
+@@ -32,7 +32,7 @@ inline void IntrCopy64fun(void *_dest, v
  	__int64* src = (__int64 *)_src;
  
  	for (unsigned i = 0; i < size; ++i)
@@ -100,7 +106,7 @@ Description: support non-x86 systems via libsimde-dev
  }
  
  
-@@ -46,7 +46,7 @@
+@@ -46,7 +46,7 @@ template <unsigned SIZE> struct IntrCopy
  		__int64* src = (__int64*)_src;
  
  		for (unsigned i = 0; i < SIZE; ++i)
@@ -109,16 +115,18 @@ Description: support non-x86 systems via libsimde-dev
  	}
  };
  
-@@ -95,4 +95,4 @@
+@@ -95,4 +95,4 @@ template <unsigned SIZE> struct IntrCopy
  
  #endif
  
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/kmc_core/kmc.h
+===================================================================
 --- kmc.orig/kmc_core/kmc.h
 +++ kmc/kmc_core/kmc.h
-@@ -1523,6 +1523,8 @@
+@@ -1523,6 +1523,8 @@ template <unsigned SIZE> KMC::Stage2Resu
  #ifdef __APPLE__
  	sort_func = RadixSort::RadixSortMSD<CKmer<SIZE>, SIZE>;
  	CSmallSort<SIZE>::Adjust(384);
@@ -127,9 +135,11 @@ Description: support non-x86 systems via libsimde-dev
  #else	
  	auto proc_name = CCpuInfo::GetBrand();
  	bool is_intel = CCpuInfo::GetVendor() == "GenuineIntel";
+Index: kmc/kmc_core/raduls.h
+===================================================================
 --- kmc.orig/kmc_core/raduls.h
 +++ kmc/kmc_core/raduls.h
-@@ -24,6 +24,7 @@
+@@ -24,6 +24,7 @@ namespace RadulsSort
  	template<typename KMER_T>
  	void RadixSortMSD_SSE2(KMER_T* kmers, KMER_T* tmp, uint64 n_recs, uint32 byte, uint32 n_threads, CMemoryPool* pmm_radix_buf);
  
@@ -137,7 +147,7 @@ Description: support non-x86 systems via libsimde-dev
  	template<typename KMER_T>
  	void RadixSortMSD_SSE41(KMER_T* kmers, KMER_T* tmp, uint64 n_recs, uint32 byte, uint32 n_threads, CMemoryPool* pmm_radix_buf);
  
-@@ -32,8 +33,9 @@
+@@ -32,8 +33,9 @@ namespace RadulsSort
  
  	template<typename KMER_T>
  	void RadixSortMSD_AVX2(KMER_T* kmers, KMER_T* tmp, uint64 n_recs, uint32 byte, uint32 n_threads, CMemoryPool* pmm_radix_buf);
@@ -149,9 +159,11 @@ Description: support non-x86 systems via libsimde-dev
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/kmc_core/raduls_impl.h
+===================================================================
 --- kmc.orig/kmc_core/raduls_impl.h
 +++ kmc/kmc_core/raduls_impl.h
-@@ -759,7 +759,7 @@
+@@ -759,7 +759,7 @@ namespace RadulsSort
  #define RADULS_RADIX_SORT_FUNNAME RadixSortMSD_AVX
  #elif defined(__SSE4_1__)
  #define RADULS_RADIX_SORT_FUNNAME RadixSortMSD_SSE41
@@ -160,16 +172,18 @@ Description: support non-x86 systems via libsimde-dev
  #define RADULS_RADIX_SORT_FUNNAME RadixSortMSD_SSE2
  #endif
  
-@@ -798,4 +798,4 @@
+@@ -798,4 +798,4 @@ namespace RadulsSort
  
  #endif
  
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/kmc_core/splitter.cpp
+===================================================================
 --- kmc.orig/kmc_core/splitter.cpp
 +++ kmc/kmc_core/splitter.cpp
-@@ -361,7 +361,7 @@
+@@ -361,7 +361,7 @@ bool CSplitter::GetSeq(char *seq, uint32
  				if (!both_strands && is_rev_comp) //if read is reversed and kmc was run to count all (not only canonical) kmers read must be transformed back
  				{
  					//static const char rev_maping[] = "=TGMCRSVAWYHKDBN";
@@ -178,7 +192,7 @@ Description: support non-x86 systems via libsimde-dev
  					uint32 n_bytes = l_seq / 2;
  					uint64_t pos_after = pos + l_seq;
  					pos = pos_after;
-@@ -380,7 +380,7 @@
+@@ -380,7 +380,7 @@ bool CSplitter::GetSeq(char *seq, uint32
  				}
  				else
  				{
@@ -187,7 +201,7 @@ Description: support non-x86 systems via libsimde-dev
  					uint32 n_bytes = l_seq / 2;
  					for (uint32_t ii = 0; ii < n_bytes; ++ii)
  					{
-@@ -1043,4 +1043,4 @@
+@@ -1043,4 +1043,4 @@ template bool CSplitter::ProcessReadsSma
  template class CWSmallKSplitter<uint32>;
  template class CWSmallKSplitter<uint64>;
  
diff --git a/debian/patches/spelling.patch b/debian/patches/spelling.patch
index 22ed028..fdcaf20 100644
--- a/debian/patches/spelling.patch
+++ b/debian/patches/spelling.patch
@@ -4,9 +4,11 @@ Forwarded: no
 Last-Update: 2020-12-10
 ---
 This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: kmc/kmc_tools/kmc2_db_reader.h
+===================================================================
 --- kmc.orig/kmc_tools/kmc2_db_reader.h
 +++ kmc/kmc_tools/kmc2_db_reader.h
-@@ -1434,7 +1434,7 @@
+@@ -1434,7 +1434,7 @@ template<unsigned SIZE> CKMC2DbReaderSor
  	my_fseek(kmc_pre, 4, SEEK_SET);
  	if (fread(LUTS, sizeof(uint64), lut_recs, kmc_pre) != lut_recs)
  	{
@@ -15,7 +17,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  		exit(1);
  	}
  	fclose(kmc_pre);
-@@ -1934,7 +1934,7 @@
+@@ -1934,7 +1934,7 @@ template<unsigned SIZE> CKMC2DbReader<SI
  		db_reader_counters_only = std::make_unique<CKMC2DbReaderCountersOnly<SIZE>>(header, desc);
  		break;
  	default: //should never be here
@@ -24,9 +26,11 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  		exit(1);
  	}
  }
+Index: kmc/kmc_tools/parameters_parser.cpp
+===================================================================
 --- kmc.orig/kmc_tools/parameters_parser.cpp
 +++ kmc/kmc_tools/parameters_parser.cpp
-@@ -149,7 +149,7 @@
+@@ -149,7 +149,7 @@ void CParametersParser::read_input_fastq
  				config.filtering_params.input_file_type = CFilteringParams::file_type::fastq;
  				break;
  			default:
@@ -35,7 +39,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  				exit(1);
  				break;
  			}
-@@ -219,7 +219,7 @@
+@@ -219,7 +219,7 @@ void CParametersParser::read_filter_para
  		}
  		else
  		{
@@ -44,7 +48,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  		}
  		++pos;
  	}
-@@ -263,7 +263,7 @@
+@@ -263,7 +263,7 @@ void CParametersParser::read_input_desc(
  		}
  		else
  		{
@@ -53,7 +57,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  			exit(1);
  		}
  	}
-@@ -575,7 +575,7 @@
+@@ -575,7 +575,7 @@ bool CParametersParser::read_output_desc
  		}
  		else
  		{
@@ -62,7 +66,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  			Usage();
  			exit(1);
  		}
-@@ -635,7 +635,7 @@
+@@ -635,7 +635,7 @@ void CParametersParser::Parse()
  	}
  	else
  	{
@@ -71,7 +75,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  		Usage();
  		exit(1);
  	}
-@@ -655,7 +655,7 @@
+@@ -655,7 +655,7 @@ void CParametersParser::Parse()
  		read_output_fastq_desc();
  		if (config.filtering_params.use_float_value && config.filtering_params.filter_mode != CFilteringParams::FilterMode::normal)
  		{
@@ -80,16 +84,18 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  			exit(1);
  		}
  	}
-@@ -954,4 +954,4 @@
+@@ -954,4 +954,4 @@ void CParametersParser::SetThreads()
  
  
  
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/kmc_tools/parser.cpp
+===================================================================
 --- kmc.orig/kmc_tools/parser.cpp
 +++ kmc/kmc_tools/parser.cpp
-@@ -140,7 +140,7 @@
+@@ -140,7 +140,7 @@ void CParser::parseInputLine(const std::
  					desc.cutoff_max = atoi(tmp.c_str() + 3);
  					continue;
  				}
@@ -98,7 +104,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  				exit(1);
  			}
  
-@@ -232,7 +232,7 @@
+@@ -232,7 +232,7 @@ void CParser::parseOtuputParamsLine()
  				}
  				continue;
  			}
@@ -107,7 +113,7 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  			exit(1);
  		}
  	}
-@@ -253,4 +253,4 @@
+@@ -253,4 +253,4 @@ bool CParser::nextLine(std::string& line
  	}
  }
  
diff --git a/debian/patches/support-mixed-march.patch b/debian/patches/support-mixed-march.patch
index 6a36cdd..8c4b123 100644
--- a/debian/patches/support-mixed-march.patch
+++ b/debian/patches/support-mixed-march.patch
@@ -12,6 +12,8 @@ Forwarded: not-needed
 Last-Update: 2021-08-21
 ---
 This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: kmc/kmc_core/raduls_avx.cpp
+===================================================================
 --- kmc.orig/kmc_core/raduls_avx.cpp
 +++ kmc/kmc_core/raduls_avx.cpp
 @@ -8,6 +8,9 @@
@@ -24,9 +26,11 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  #include "raduls_impl.h"
  
  // ***** EOF
+Index: kmc/kmc_core/raduls_impl.h
+===================================================================
 --- kmc.orig/kmc_core/raduls_impl.h
 +++ kmc/kmc_core/raduls_impl.h
-@@ -754,12 +754,20 @@
+@@ -754,12 +754,20 @@ namespace RadulsSort
  	}
  
  #if defined(__AVX2__)
@@ -47,6 +51,8 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  #define RADULS_RADIX_SORT_FUNNAME RadixSortMSD_SSE2
  #endif
  
+Index: kmc/kmc_core/raduls_sse2.cpp
+===================================================================
 --- kmc.orig/kmc_core/raduls_sse2.cpp
 +++ kmc/kmc_core/raduls_sse2.cpp
 @@ -8,6 +8,15 @@
@@ -65,6 +71,8 @@ This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
  #include "raduls_impl.h"
  
  // ***** EOF
+Index: kmc/kmc_core/raduls_sse41.cpp
+===================================================================
 --- kmc.orig/kmc_core/raduls_sse41.cpp
 +++ kmc/kmc_core/raduls_sse41.cpp
 @@ -8,6 +8,12 @@
diff --git a/debian/patches/use-shared-libs b/debian/patches/use-shared-libs
index 7c5db2a..3a4513b 100644
--- a/debian/patches/use-shared-libs
+++ b/debian/patches/use-shared-libs
@@ -6,6 +6,8 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  makefile                    | 8 ++------
  2 files changed, 6 insertions(+), 10 deletions(-)
 
+Index: kmc/kmc_tools/fastq_reader.h
+===================================================================
 --- kmc.orig/kmc_tools/fastq_reader.h
 +++ kmc/kmc_tools/fastq_reader.h
 @@ -17,8 +17,8 @@
@@ -19,16 +21,18 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  
  
  using namespace std;
-@@ -96,4 +96,4 @@
+@@ -96,4 +96,4 @@ public:
  
  #endif
  
 -// ***** EOF
 \ No newline at end of file
 +// ***** EOF
+Index: kmc/Makefile
+===================================================================
 --- kmc.orig/Makefile
 +++ kmc/Makefile
-@@ -53,14 +53,6 @@
+@@ -53,14 +53,6 @@ $(KMC_MAIN_DIR)/kmc_runner.o
  ifeq ($(UNAME_S),Darwin)
  	RADULS_OBJS =
  
@@ -43,7 +47,7 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  	LIB_KMC_CORE = $(OUT_BIN_DIR)/libkmc_core.mac.a
  else
  	RADULS_OBJS = \
-@@ -69,14 +61,6 @@
+@@ -69,14 +61,6 @@ else
  	$(KMC_MAIN_DIR)/raduls_avx2.o \
  	$(KMC_MAIN_DIR)/raduls_avx.o
  
@@ -58,6 +62,8 @@ From: Debian Med Packaging Team <debian-med-packaging@lists.alioth.debian.org>
  	LIB_KMC_CORE = $(OUT_BIN_DIR)/libkmc_core.a
  endif
  
+Index: kmc/kmc_core/fastq_reader.h
+===================================================================
 --- kmc.orig/kmc_core/fastq_reader.h
 +++ kmc/kmc_core/fastq_reader.h
 @@ -15,8 +15,8 @@
diff --git a/kmc.sln b/kmc.sln
index 1b5a16d..4cbc0f0 100644
--- a/kmc.sln
+++ b/kmc.sln
@@ -41,7 +41,8 @@ Global
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|Mixed Platforms.Build.0 = Debug|Win32
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|Win32.ActiveCfg = Debug|Win32
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|Win32.Build.0 = Debug|Win32
-		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|x64.ActiveCfg = Debug|Win32
+		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|x64.ActiveCfg = Debug|x64
+		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Debug|x64.Build.0 = Debug|x64
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Release|Mixed Platforms.ActiveCfg = Release|x64
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Release|Mixed Platforms.Build.0 = Release|x64
 		{8939AD12-23D5-469C-806B-DC3F98F8A514}.Release|Win32.ActiveCfg = Release|Win32
@@ -52,7 +53,8 @@ Global
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|Mixed Platforms.Build.0 = Debug|Win32
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|Win32.ActiveCfg = Debug|Win32
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|Win32.Build.0 = Debug|Win32
-		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|x64.ActiveCfg = Debug|Win32
+		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|x64.ActiveCfg = Debug|x64
+		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Debug|x64.Build.0 = Debug|x64
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Release|Mixed Platforms.ActiveCfg = Release|x64
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Release|Mixed Platforms.Build.0 = Release|x64
 		{17823F37-86DE-4E58-B354-B84DA9EDA6A1}.Release|Win32.ActiveCfg = Release|Win32
@@ -98,7 +100,7 @@ Global
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		VisualSVNWorkingCopyRoot = .
 		SolutionGuid = {BC3A0CEE-782E-46DC-A9C0-330A04586DCF}
+		VisualSVNWorkingCopyRoot = .
 	EndGlobalSection
 EndGlobal
diff --git a/kmc_api/kmc_file.cpp b/kmc_api/kmc_file.cpp
index e292148..456a7d7 100644
--- a/kmc_api/kmc_file.cpp
+++ b/kmc_api/kmc_file.cpp
@@ -249,7 +249,7 @@ bool CKMCFile::ReadParamsFrom_prefix_file_buf(uint64 &size, open_mode _open_mode
 		}
 		else
 		{
-			prefixFileBufferForListingMode = std::make_unique<CPrefixFileBufferForListingMode>(file_pre, last_data_index, lut_prefix_length);
+			prefixFileBufferForListingMode = std::make_unique<CPrefixFileBufferForListingMode>(file_pre, last_data_index, lut_prefix_length, false, total_kmers);
 		}
 
 		sufix_size = (kmer_length - lut_prefix_length) / 4;
@@ -311,7 +311,7 @@ bool CKMCFile::ReadParamsFrom_prefix_file_buf(uint64 &size, open_mode _open_mode
 		}
 		else
 		{
-			prefixFileBufferForListingMode = std::make_unique<CPrefixFileBufferForListingMode>(file_pre, last_data_index, lut_prefix_length);
+			prefixFileBufferForListingMode = std::make_unique<CPrefixFileBufferForListingMode>(file_pre, last_data_index, lut_prefix_length, true, total_kmers);
 		}
 
 		sufix_size = (kmer_length - lut_prefix_length) / 4;
diff --git a/kmc_api/kmc_file.h b/kmc_api/kmc_file.h
index a6cfb06..3f9ad38 100644
--- a/kmc_api/kmc_file.h
+++ b/kmc_api/kmc_file.h
@@ -43,22 +43,32 @@ class CKMCFile
 		uint64_t leftToRead{};
 		uint64 prefixMask; //for kmc2 db
 		FILE* file;
+		bool isKMC1 = false;
+		uint64_t totalKmers; //for
+
 		void reload()
 		{
+			assert(leftToRead);
 			buffPosInFile += buffSize;
 			buffSize = (std::min)(buffCapacity, leftToRead);
 			auto readed = fread(buff, 1, 8 * buffSize, file);
 			assert(readed == 8 * buffSize);
+
+			if (isKMC1 && buffSize == leftToRead) //last read, in case of KMC1 guard must be added, fread will read `k` from db instead of guard, fixes #180
+				buff[buffSize - 1] = totalKmers;
+
 			leftToRead -= buffSize;
 			posInBuf = 0;
 		}
 	public:
-		CPrefixFileBufferForListingMode (FILE* file, uint64_t wholeLutSize, uint64_t lutPrefixLen)
+		CPrefixFileBufferForListingMode(FILE* file, uint64_t wholeLutSize, uint64_t lutPrefixLen, bool isKMC1, uint64_t totalKmers)
 			:
 			buff(new uint64_t[buffCapacity]),
 			leftToRead(wholeLutSize),
 			prefixMask((1ull << (2 * lutPrefixLen)) - 1),
-			file(file)
+			file(file),
+			isKMC1(isKMC1),
+			totalKmers(totalKmers)
 		{
 			my_fseek(file, 4 + 8, SEEK_SET); //	skip KMCP and LUT[0] (always = 0)
 		}
diff --git a/tests/kmc_CLI/check-prerequisites.py b/tests/kmc_CLI/check-prerequisites.py
new file mode 100644
index 0000000..1d58bf1
--- /dev/null
+++ b/tests/kmc_CLI/check-prerequisites.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+import hashlib
+import os
+import sys
+import subprocess
+
+if len(sys.argv) < 2:
+    print("Usage: {} <data_dir>".format(sys.argv[0]))
+    sys.exit(1)
+
+script_path = os.path.dirname(os.path.abspath(__file__))
+
+def compute_md5(path):
+    with open(path, "rb") as f:
+        file_hash = hashlib.md5()
+        while chunk := f.read(8192):
+            file_hash.update(chunk)        
+        return file_hash.hexdigest()
+
+def verify_md5(baseDir, filePath, pattern):    
+    cached_path_md5_file = os.path.join(baseDir, "cached", "md5", filePath + ".md5")    
+    
+    if not os.path.exists(os.path.dirname(cached_path_md5_file)):
+        os.makedirs(os.path.dirname(cached_path_md5_file))
+    if not os.path.exists(cached_path_md5_file):        
+        md5 = compute_md5(os.path.join(baseDir, filePath))
+        with open (cached_path_md5_file, "w") as f:
+            f.write(md5)
+    else:
+        with open (cached_path_md5_file) as f:
+            md5 = f.read()
+
+    return md5 == pattern
+
+with open(os.path.join(script_path, "prerequisite-files.txt")) as f:
+    for line in f:
+        line = line.strip()        
+        path = line[0:-33]
+        md5 = line[-32:]
+        
+        full_path = os.path.join(sys.argv[1], path)
+        if not os.path.exists(full_path):
+            print("{} does not exists".format(full_path))
+            sys.exit(1)
+        print("checking {}".format(full_path))
+    
+        if not verify_md5(sys.argv[1], path, md5):        
+            print("Invalid md5 for {}".format(full_path))
+            sys.exit(1)
\ No newline at end of file
diff --git a/tests/kmc_CLI/data/issue-180/input.fa b/tests/kmc_CLI/data/issue-180/input.fa
new file mode 100644
index 0000000..917470f
--- /dev/null
+++ b/tests/kmc_CLI/data/issue-180/input.fa
@@ -0,0 +1,2 @@
+>palindrome
+AACTGACATGTCAGTT
diff --git a/tests/kmc_CLI/data/issue-180/pattern.dump b/tests/kmc_CLI/data/issue-180/pattern.dump
new file mode 100644
index 0000000..fd99310
--- /dev/null
+++ b/tests/kmc_CLI/data/issue-180/pattern.dump
@@ -0,0 +1,6 @@
+AACTG	2
+ACATG	2
+ACTGA	2
+ATGTC	2
+CTGAC	2
+TGACA	2
diff --git a/tests/kmc_CLI/prepare_small_fastq_tests.py b/tests/kmc_CLI/prepare_small_fastq_tests.py
new file mode 100644
index 0000000..18249b5
--- /dev/null
+++ b/tests/kmc_CLI/prepare_small_fastq_tests.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+
+import subprocess
+import os
+import sys
+import queue
+import threading
+
+if len(sys.argv) < 5:
+    print("Usage: {} <data_dir> <trivial k-mer counter path> <fileToGetPartFrom> <no. lines>".format(sys.argv[0]))
+    sys.exit(1)
+
+script_path = os.path.dirname(os.path.abspath(__file__))
+
+data_dir = sys.argv[1]
+count_progam = sys.argv[2]
+fileToGetPartFrom = os.path.join(data_dir, sys.argv[3])
+no_lines = sys.argv[4]
+
+partFilePath = os.path.join(data_dir, "cached", "small.fastq", os.path.basename(fileToGetPartFrom) + ".part.{}.fq".format(no_lines))
+if not os.path.exists(os.path.dirname(partFilePath)):
+    os.makedirs(os.path.dirname(partFilePath))
+if not os.path.exists(partFilePath):
+    subprocess.call(["zcat {} | head -n {} > {}".format(fileToGetPartFrom, no_lines, partFilePath)], shell=True)
+
+q=queue.Queue()
+print_q = queue.Queue()
+
+
+def count(k, ci, cx, cs):
+    o = os.path.join(partFilePath + ".pattern-res", "k{}.ci{}.cx{}.cs{}".format(k, ci, cx, cs))    
+    if not os.path.exists(o):
+        os.makedirs(o)    
+    o = os.path.join(o, "kmers")
+    if not os.path.exists(o) or not os.path.exists(o+".stats"):
+        cmd = "{} -k {} -ci {} -cx {} -cs {} {} {}".format(count_progam, k, ci, cx, cs, partFilePath, o)
+        print_q.put((cmd))        
+        out = open(o + ".stdout", 'w')
+        err = open(o + ".stderr", 'w')
+        subprocess.call([cmd], shell=True,stdout=out, stderr=err)
+
+
+def print_worker():
+	while True:
+		(cmd) = print_q.get()
+		print(cmd)
+		print_q.task_done()
+
+def worker():
+	while True:
+		(k, ci, cx, cs) = q.get()
+		count(k, ci, cx, cs)
+		q.task_done()
+
+num_thread = 32
+for i in range(0,num_thread):
+	t=threading.Thread(target=worker)
+	t.daemon=True
+	t.start()
+
+t=threading.Thread(target=print_worker)
+t.daemon=True
+t.start()
+
+for k in range(1, 257):
+    q.put((k, 2, 1000000000, 255))    
+	
+q.join()
+print_q.join()
\ No newline at end of file
diff --git a/tests/kmc_CLI/prerequisite-files.txt b/tests/kmc_CLI/prerequisite-files.txt
new file mode 100644
index 0000000..c532f47
--- /dev/null
+++ b/tests/kmc_CLI/prerequisite-files.txt
@@ -0,0 +1,11 @@
+F.vesca/SRR072005.fastq.gz 89c567dea115f34868a344139cc385f7
+F.vesca/SRR072006.fastq.gz 141dd19f0a1289dfc8e3e9d350654d37
+F.vesca/SRR072007.fastq.gz 5b75b521c3dffc0ba3773c0eaab12e62
+F.vesca/SRR072008.fastq.gz c42b0135d6cd255f1adc773b39199e7d
+F.vesca/SRR072009.fastq.gz d780afae41fffd302b45e56b6311fed3
+F.vesca/SRR072010.fastq.gz ce616ebd486ea7421327b3e95c64c6a7
+F.vesca/SRR072011.fastq.gz c6586e181b11e7a9758881cdd8f8e6f2
+F.vesca/SRR072012.fastq.gz eca25ff92a7d7b978b7daf3140093418
+F.vesca/SRR072013.fastq.gz 8110d6be941fc5a7d52038fb935f57d5
+F.vesca/SRR072014.fastq.gz 5f5b7b08b9df896516981009aaa2905f
+F.vesca/SRR072029.fastq.gz 4792c30f68d8f1d2970a31e6d6599379
diff --git a/tests/kmc_CLI/run_small_fastq_tests.py b/tests/kmc_CLI/run_small_fastq_tests.py
new file mode 100644
index 0000000..cedb858
--- /dev/null
+++ b/tests/kmc_CLI/run_small_fastq_tests.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+
+import subprocess
+import os
+import sys
+import filecmp
+
+if len(sys.argv) < 5:
+    print("Usage: {} <data_dir> <kmc_path> <kmc_tools_path> <kmc_dump_path>".format(sys.argv[0]))
+    sys.exit(1)
+
+script_path = os.path.dirname(os.path.abspath(__file__))
+
+data_dir = sys.argv[1]
+kmc = sys.argv[2]
+kmc_tools = sys.argv[3]
+kmc_dump = sys.argv[4]
+
+inputDir = os.path.join(data_dir, "cached", "small.fastq")
+
+def read_params_from_dir_name(dir_name):
+    parts = dir_name.split(".")
+    res = ""
+    for part in parts:
+        if part.startswith("k"):
+            res += " -k{}".format(part[1:])
+        elif part.startswith("ci"):
+            res += " -ci{}".format(part[2:])
+        elif part.startswith("cx"):
+            res += " -cx{}".format(part[2:])            
+        elif part.startswith("cs"):
+            res += " -cs{}".format(part[2:])            
+        elif part.startswith("b"):
+            res += " -b"
+    return res
+
+def is_sorted(kmc_db):
+    command = "{} info o".format(kmc_tools)
+    print(command)
+    proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+    stdout, stderr = proc.communicate()
+    stdout = stdout.decode("utf-8")
+    for line in stdout.split('\n'):
+        if "database format" in line:
+            return "KMC1" in line
+    print("Error: cannot read kmc db format")
+    sys.exit(1)
+
+def compare_stats(kmc_stats, pattern_file_path):
+    kmc = dict()
+    pattern = dict()
+    for line in kmc_stats.split('\n'):
+        if "No. of k-mers below min. threshold" in line:
+            kmc["n_ci"] = line.split(":")[-1].strip()
+        elif "No. of k-mers above max. threshold" in line:
+            kmc["n_cx"] = line.split(":")[-1].strip()
+        elif "No. of unique k-mers" in line:
+            kmc["n_unique"] = line.split(":")[-1].strip()
+        elif "No. of unique counted k-mers" in line:
+            kmc["n_unique_cnt"] = line.split(":")[-1].strip()
+        elif "Total no. of k-mers" in line:
+            kmc["n_kmers"] = line.split(":")[-1].strip()
+        elif "Total no. of reads" in line:
+            kmc["n_seqs"] = line.split(":")[-1].strip()
+
+    with open(pattern_file_path) as f:
+        for line in f:
+            line = line.strip()
+            if "Total unique k-mers below min cutoff:" in line:
+                pattern["n_ci"] = line.split(":")[-1].strip()
+            elif "Total unique k-mers above max cutoff:" in line:
+                pattern["n_cx"] = line.split(":")[-1].strip()
+            elif "Total unique k-mers:" in line:
+                pattern["n_unique"] = line.split(":")[-1].strip()
+
+            elif "Total unique counted k-mers:" in line:
+                pattern["n_unique_cnt"] = line.split(":")[-1].strip()
+            elif "Total k-mers:" in line:
+                pattern["n_kmers"] = line.split(":")[-1].strip()
+            elif "Total sequences:" in line:
+                pattern["n_seqs"] = line.split(":")[-1].strip()                                
+    return kmc == pattern
+
+def run_for_file(input):
+    pattern_dir = input + ".pattern-res"
+    dirs_to_run = []
+    for x in os.listdir(pattern_dir):
+        if os.path.isfile(os.path.join(pattern_dir, x)):
+            print("Unexpected file " + os.path.join(pattern_dir, x))
+            sys.exit(1)
+        dirs_to_run.append(os.path.basename(x))
+    
+    dirs_to_run.sort()
+    for x in dirs_to_run:
+        kmc_params = read_params_from_dir_name(x)
+        command = "/usr/bin/time -v {} {} -v -hp {} o .".format(kmc, kmc_params, input)
+        print(command)
+        proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = True)
+        stdout, stderr = proc.communicate()
+        stdout = stdout.decode("utf-8")
+        print(stderr.decode("utf-8"))
+        print(stdout)
+        
+
+        if not compare_stats(stdout, os.path.join(pattern_dir, x, "kmers.stats")):
+            print("Error: summary statistics does not match")
+            sys.exit(1)
+
+        db = "o"
+
+        pattern_dump_path = os.path.join(pattern_dir, x, "kmers")
+        if not is_sorted("o"):
+            command = "/usr/bin/time -v {} -hp transform o sort o.sorted".format(kmc_tools)
+            print(command)
+            subprocess.call([command], shell = True)
+            db = "o.sorted"
+
+            #verify kmc_tools transform db dump -s db.sorted.dump
+            command = "/usr/bin/time -v {} -hp transform o dump -s o.sorted.dump".format(kmc_tools)
+            print(command)
+            subprocess.call([command], shell = True)
+
+            print("compare o.sorted.dump (from kmc_tools dump -s) and {}".format(pattern_dump_path))
+            if not filecmp.cmp("o.sorted.dump", pattern_dump_path):
+                print("Error: o.sorted.dump (from kmc_tools dump -s) and {} differs".format(db, pattern_dump_path))
+                sys.exit(1)
+
+        command = "/usr/bin/time -v {} -hp transform {} dump {}.dump".format(kmc_tools, db, db)
+        print(command)
+        subprocess.call([command], shell = True)
+                
+        print("compare {}.dump and {}".format(db, pattern_dump_path))
+        if not filecmp.cmp("{}.dump".format(db), pattern_dump_path):
+            print("{}.dump and {} differs".format(db, pattern_dump_path))
+            sys.exit(1)
+
+        command = "/usr/bin/time -v {} {} {}.dump".format(kmc_dump, db, db)
+        print(command)
+        subprocess.call([command], shell = True)
+
+        print("compare {}.dump (from kmc_dump) and {}".format(db, pattern_dump_path))
+        if not filecmp.cmp("{}.dump".format(db), pattern_dump_path):
+            print("{}.dump (from kmc_dump) and {} differs".format(db, pattern_dump_path))
+            sys.exit(1)
+        
+for x in os.listdir(inputDir):
+    fullPath = os.path.join(inputDir, x)
+    if not os.path.isfile(fullPath):
+        continue
+    run_for_file(fullPath)    
+
diff --git a/tests/kmc_CLI/trivial-k-mer-counter/Makefile b/tests/kmc_CLI/trivial-k-mer-counter/Makefile
new file mode 100644
index 0000000..9124781
--- /dev/null
+++ b/tests/kmc_CLI/trivial-k-mer-counter/Makefile
@@ -0,0 +1,16 @@
+CC = g++
+CFLAGS = -std=c++20 -O3 -Wall -pedantic-errors
+
+all: bin/counter
+
+main.o: main.cpp
+	$(CC) $(CFLAGS) -c -o $@ main.cpp
+
+bin/counter: main.o
+	mkdir -p bin
+	$(CC) $(CFLAGS) -o $@ $^ -lz 
+
+
+clean:
+	rm -f *.o
+	rm -rf bin	
\ No newline at end of file
diff --git a/tests/kmc_CLI/trivial-k-mer-counter/main.cpp b/tests/kmc_CLI/trivial-k-mer-counter/main.cpp
new file mode 100644
index 0000000..d440301
--- /dev/null
+++ b/tests/kmc_CLI/trivial-k-mer-counter/main.cpp
@@ -0,0 +1,333 @@
+#include <iostream>
+#include <vector>
+#include <sstream>
+#include <fstream>
+#include <memory>
+#include <algorithm>
+#include <unordered_map>
+
+#include <zlib.h>
+using namespace std;
+
+struct Params
+{
+    vector<string> inputPaths;
+    string outputPath;
+    uint64_t kmerLen = 25;
+    uint64_t cutoffMin = 2;
+    uint64_t cutoffMax = 1000000000;
+    uint64_t countMax = 255;
+    bool canonical = true;
+};
+
+
+class Counter
+{
+    const Params& params;
+    uint64_t nSeqs{};
+
+    class LineReader
+    {
+        gzFile file;
+        static constexpr uint64_t buff_capacity = 1ull << 24;
+        uint64_t buff_pos = 0;
+        uint64_t buff_size = 0;
+        std::unique_ptr<uint8_t[]> buff;
+        
+        bool read_char(uint8_t& c)
+        {
+            if(buff_pos == buff_size)
+            {
+                buff_pos = 0;
+                buff_size = gzfread(buff.get(), 1, buff_capacity, file);
+            }
+            if(buff_size == 0)
+                return false;
+            c = buff[buff_pos++];
+            return true;
+        }
+
+        public:
+        LineReader(gzFile file):
+            file(file),
+            buff(make_unique_for_overwrite<uint8_t[]>(buff_capacity))
+            {
+                
+            }
+        pair<bool, string> NextLine()
+        {
+            string line;
+            uint8_t c;
+            bool any = false;
+            while (read_char(c))
+            {
+                if(c == '\r')
+                    continue;
+                any = true;
+                if (c != '\n')
+                    line.push_back((char)c);
+                else 
+                    break;
+            }
+            return make_pair(any, line);
+        }
+    };
+
+    class SeqReader
+    {
+        LineReader& lineReader;
+        bool is = false;
+        string prevLine;
+        
+        string nextSeqFastq()
+        {
+            auto [is2, seq] = lineReader.NextLine();
+            auto [is3, qual_header] = lineReader.NextLine();
+            auto [is4, qual] = lineReader.NextLine();
+            
+            if (!is2 || !is3 || !is4)
+            {
+                cerr << "Error reading file " << __FILE__ << "\t" << __LINE__ << "\n";
+                exit(1);
+            }
+
+            std::tie(is, prevLine) = lineReader.NextLine();
+
+            return seq;
+        }
+
+        string nextSeqFasta()
+        {
+            string seq;
+            while (true)
+            {
+                std::tie(is, prevLine) = lineReader.NextLine();
+                if(!is)
+                    return seq;
+                
+                if (prevLine.size() == 0)
+                    return seq;
+
+                if (prevLine[0] == '>')
+                    return seq;
+
+                seq += prevLine;                
+            }   
+        }
+
+        public:
+        SeqReader(LineReader& lineReader) :
+            lineReader(lineReader)
+        {
+            std::tie(is, prevLine) = lineReader.NextLine();
+        }
+        pair<bool, string> NextSeq()
+        {
+            if (!is)
+                return make_pair(false, "");
+        
+            if (prevLine.size() == 0)
+            {
+                cerr << "Error: something is wrong with this file " << __FILE__ << "\t" << __LINE__ << "\n";
+                exit(1);
+            }
+            if (prevLine[0] == '@')
+                return make_pair(true, nextSeqFastq());
+            if (prevLine[0] == '>')
+                return make_pair(true, nextSeqFasta());                
+            cerr << "Error: unsupported file format. I don't know how to interpret line: " << prevLine << "\n";                
+            cerr << __FILE__ << "\t" << __LINE__ << "\n";
+            exit(1);        
+        }
+    };
+
+    string get_rev_compl(const std::string& kmer)
+    {
+        string res;
+        res.reserve(kmer.size());
+        for (auto it = kmer.crbegin() ; it != kmer.crend() ; ++it)
+        {            
+            switch (*it)
+            {
+            case 'A': res.push_back('T'); break;
+            case 'C': res.push_back('G'); break;
+            case 'G': res.push_back('C'); break;
+            case 'T': res.push_back('A'); break;
+            default:
+                cerr << "Error: wrong symbol in k-mer: " << kmer << "\n";
+                exit(1);
+            }
+        }
+        return res;
+    }
+    void canonicalize(string& kmer)
+    {
+        auto rev = get_rev_compl(kmer);
+        if(rev < kmer)
+            kmer = rev;
+    }
+
+    std::unordered_map<string, uint64_t> m;
+
+    void processFile(const std::string& fname)
+    {
+        cerr << "Processing file " << fname << "\n";
+        auto gzfile = gzopen(fname.c_str(), "r");
+        if(!gzfile)
+        {
+            cerr << "Error: cannot open file " << fname << "\n";
+            exit(1);
+        }
+        LineReader lineReader(gzfile);
+        SeqReader seqReader(lineReader);
+
+        for (auto [is, seq] = seqReader.NextSeq(); is; tie(is, seq) = seqReader.NextSeq())
+        {
+            //if (nSeqs % 100000 == 0)
+            //    cout << nSeqs << "\n";
+            ++nSeqs;
+
+            if (seq.size() < params.kmerLen)
+                continue;
+            //cout << "seq:\n" << seq << "\n";            
+            
+            
+            transform(seq.begin(), seq.end(), seq.begin(), ::toupper);
+            uint64_t endPos = seq.size() - params.kmerLen + 1;            
+            for (uint64_t pos = 0; pos < endPos ; ++pos)
+            {
+                auto kmer = seq.substr(pos, params.kmerLen);
+                auto er_symb = kmer.find_first_not_of("ACGT");
+                if (er_symb != std::string::npos)
+                {                
+                    pos += er_symb;
+                    continue;
+                }
+                if (params.canonical)
+                    canonicalize(kmer);                
+                ++m[kmer];
+            }
+        }
+        gzclose(gzfile);
+    }
+
+    public:
+    Counter(const Params& params):
+        params(params)
+        {
+            for (const auto& fname : params.inputPaths)            
+               processFile(fname);
+            
+            vector<pair<string, uint64_t>> kmers;
+            cerr << "Take k-mers from unordered map to vector...";
+            uint64_t nCutoffMin{}, nCutoffMax{};
+            uint64_t tot_kmers{};
+            for (const auto& [kmer, count] : m)
+            {
+                tot_kmers += count;
+                if (count < params.cutoffMin)
+                    ++nCutoffMin;
+                else if(count > params.cutoffMax)
+                    ++nCutoffMax;
+                else 
+                    kmers.emplace_back(kmer, count > params.countMax ? params.countMax : count);
+            }
+            cerr << "\n";
+
+            ofstream stats_file(params.outputPath + ".stats");
+            if(!stats_file)
+            {
+                cerr << "Error: cannot open file " << params.outputPath + ".stats" << "\n";
+                exit(1);
+            }
+            stats_file << "Total unique k-mers below min cutoff:\t" << nCutoffMin << "\n";
+            stats_file << "Total unique k-mers above max cutoff:\t" << nCutoffMax << "\n";            
+            stats_file << "Total unique k-mers:\t" << m.size() << "\n";            
+            stats_file << "Total unique counted k-mers:\t" << kmers.size() << "\n";
+            stats_file << "Total k-mers:\t" << tot_kmers << "\n";            
+            stats_file << "Total sequences:\t" << nSeqs << "\n";
+
+            cerr << "Sorting k-mers...";
+            sort(kmers.begin(), kmers.end());
+            cerr << "\n";
+
+            ofstream out(params.outputPath);
+            if(!out)
+            {
+                cerr << "Error: cannot open file " << params.outputPath << "\n";
+                exit(1);
+            }
+
+            for (const auto& [kmer, count] : kmers)
+                out << kmer << "\t" << count << "\n";
+
+            
+        }
+    
+};
+
+template<typename T>
+void ParseToType(const std::string& parseFrom, T& parseTo)
+{
+    istringstream s(parseFrom);
+    if(!(s >> parseTo))
+    {
+        std::cerr << "Error: cannot parse " << parseFrom << "\n";
+        exit(1);
+    }
+}
+
+Params parse_params(int argc, char**argv)
+{
+    if(argc < 3)
+    {
+        cerr << "Usage: " << argv[0] << " [-k<k>] [-ci<ci>] [-cx<cx>] [-cs<cs>] [-b] [@]<inputFile(s)> <outputFile>\n";
+        exit(1);
+    }
+    Params p;
+    for (int i = 1 ; i < argc - 2; ++i)
+    {
+        string param = argv[i];
+        if (param == "-k")
+            ParseToType(argv[++i], p.kmerLen);
+        else if (param == "-ci")
+            ParseToType(argv[++i], p.cutoffMin);
+        else if (param == "-cx")
+            ParseToType(argv[++i], p.cutoffMax);
+        else if (param == "-cs")
+            ParseToType(argv[++i], p.countMax);            
+        else if (param == "-b")
+            p.canonical = false;
+        else
+        {
+            cerr << "Error: unknown parameter: " << param << "\n";
+            exit(1);
+        }
+    }
+
+    p.outputPath = argv[argc-1];
+    string inputPath = argv[argc-2];
+    if (inputPath[0] == '@')
+    {
+        ifstream in(inputPath);
+        if(!in)
+        {
+            cerr << "Error: cannot open file " << inputPath <<"\n";
+            exit(1);
+        }
+        string path;
+        while (getline(in, path))
+            p.inputPaths.push_back(path);
+    }
+    else
+        p.inputPaths.push_back(inputPath);
+    
+
+    return p;
+}
+
+int main(int argc, char**argv)
+{
+    auto params = parse_params(argc, argv);
+    Counter counter(params);
+}
\ No newline at end of file