diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
new file mode 100644
index 0000000..ba64551
--- /dev/null
+++ b/.github/workflows/cmake.yml
@@ -0,0 +1,41 @@
+name: CMake
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+env:
+  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
+  BUILD_TYPE: Release
+
+jobs:
+  build:
+    # The CMake configure and build commands are platform agnostic and should work equally
+    # well on Windows or Mac.  You can convert this to a matrix build if you need
+    # cross-platform coverage.
+    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+    
+    - name: Install Dependencies
+      run: sudo apt-get update && sudo apt-get install -yq libboost-all-dev
+      
+    - name: Configure CMake
+      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
+      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
+      run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTING=yes
+
+    - name: Build
+      # Build your program with the given configuration
+      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
+
+    - name: Test
+      working-directory: ${{github.workspace}}/build
+      # Execute tests defined by the CMake configuration.  
+      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
+      run: ctest -C ${{env.BUILD_TYPE}}
+      
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..957453d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+
+os: linux
+arch:
+ - amd64
+ - ppc64le
+language: cpp
+
+compiler:
+  - gcc
+  - clang
+  
+before_install:
+  - sudo apt-get update -qq
+  - sudo apt-get install libboost-all-dev
+  
+script:
+  - mkdir build
+  - cd build
+  - cmake .. -DBUILD_TESTING=yes
+  - make
+  - make test
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 07b2cf9..0fec6ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ add_subdirectory( tools )
 
 # Make sure the version is in sync with
 # libgdf/include/GDF/Version.h
-set(GDF_VERSION "0.1.3")
+set(GDF_VERSION "0.1.4")
 
 # shared library API versioning (soversion) -- NOT the same as the release version
 # it follows first number
diff --git a/README b/README
deleted file mode 100644
index fcb6f0f..0000000
--- a/README
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# This file is part of libGDF.
-#
-# libGDF is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# libGDF is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with libGDF.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Copyright 2010 Martin Billinger
-
-
-A. Build Instructions (out of source build)
-
-    replace $GDF_ROOT with the (relative or absolute) path to the source
-    tree (e.g. ~/SVN/GDF/trunk).
-
-    > mkdir build
-    > cd build
-    > cmake $GDF_ROOT
-    > make
-    > make check
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ffdd901
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+[![Build Status](https://travis-ci.org/mbillingr/libgdf.svg?branch=master)](https://travis-ci.com/mbillingr/libgdf)
+[![CMake](https://github.com/mbillingr/libgdf/actions/workflows/cmake.yml/badge.svg)](https://github.com/mbillingr/libgdf/actions/workflows/cmake.yml)
+
+libGDF
+======
+
+C++ implementation of GDF - "a general dataformat for biosignals" version V2.20. 
+
+Obtaining libGDF
+----------------
+
+Use the following command to fetch the sources:
+
+    git clone https://github.com/kazemakase/libgdf.git libgdf
+    
+Dependencies
+------------
+Required: boost
+
+Build Instructions
+------------------
+
+The preferred method is to perform an out-of-source build.
+Replace `$GDF_ROOT` with the (relative or absolute) path to the source
+tree (e.g. ~/repositories/libgdf).
+
+    mkdir build
+    cd build
+    cmake $GDF_ROOT -DBUILD_TESTING=yes
+    make
+    make test
diff --git a/changelog.txt b/changelog.txt
index dfcc18e..63693bb 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,6 +1,6 @@
 
 
-  Development Head
+  Development Head (0.1.4)
 ===================
 
   Version 0.1.3
diff --git a/debian/changelog b/debian/changelog
index 9b413b9..ac6771e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+libgdf (0.1.3+git20210707.1.39e9cfb-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+  * Drop patch check-system-endianness.patch, present upstream.
+  * Drop patch compile-with-g++-11.patch, present upstream.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 20 Mar 2022 00:44:17 -0000
+
 libgdf (0.1.3-11) unstable; urgency=medium
 
   * Team upload.
diff --git a/debian/patches/check-system-endianness.patch b/debian/patches/check-system-endianness.patch
deleted file mode 100644
index a539176..0000000
--- a/debian/patches/check-system-endianness.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-Description: Avoid deprecated way of checking system endianness
- According to file /usr/include/boost/predef/detail/endian_compat.h,
- “[t]he use of BOOST_*_ENDIAN and BOOST_BYTE_ORDER is deprecated. Please
- include <boost/predef/other/endian.h> and use BOOST_ENDIAN_*_BYTE
- instead.”
- .
- This patch follows this recommendation.
-Author: Rafael Laboissière <rafael@debian.org>
-Bug-Debian: https://bugs.debian.org/975443
-Forwarded: https://github.com/mbillingr/libgdf/pull/6
-Last-Update: 2020-12-31
-
---- libgdf-0.1.3.orig/libgdf/include/GDF/Types.h
-+++ libgdf-0.1.3/libgdf/include/GDF/Types.h
-@@ -21,7 +21,7 @@
- 
- #include "Exceptions.h"
- #include <boost/cstdint.hpp>
--#include <boost/detail/endian.hpp>
-+#include <boost/predef/other/endian.h>
- #include <iostream>
- 
- namespace gdf
-@@ -74,9 +74,9 @@ namespace gdf
-     template<typename T>
-     void writeLittleEndian( std::ostream &out, T item )
-     {
--#if defined(BOOST_LITTLE_ENDIAN)
-+#if BOOST_ENDIAN_LITTLE_BYTE
-         out.write( reinterpret_cast<const char*>(&item), sizeof(item) );
--#elif defined(BOOST_BIG_ENDIAN)
-+#elif BOOST_ENDIAN_BIG_BYTE
-         const char* p = reinterpret_cast<const char*>(&item) + sizeof(item)-1;
-         for( size_t i=0; i<sizeof(item); i++ )
-             out.write( p--, 1 );
-@@ -88,9 +88,9 @@ namespace gdf
-     template<typename T>
-     void readLittleEndian( std::istream &in, T &item )
-     {
--#if defined(BOOST_LITTLE_ENDIAN)
-+#if BOOST_ENDIAN_LITTLE_BYTE
-         in.read( reinterpret_cast<char*>(&item), sizeof(item) );
--#elif defined(BOOST_BIG_ENDIAN)
-+#elif BOOST_ENDIAN_BIG_BYTE
-         char* p = reinterpret_cast<char*>(&item) + sizeof(item)-1;
-         for( size_t i=0; i<sizeof(item); i++ )
-     in.read( p--, 1 );
diff --git a/debian/patches/compile-with-g++-11.patch b/debian/patches/compile-with-g++-11.patch
deleted file mode 100644
index 7a73486..0000000
--- a/debian/patches/compile-with-g++-11.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-Description: Compile against g++ 11
-Author: Rafael Laboissière <rafael@debian.org>
-Bug-Debian: https://bugs.debian.org/984105
-Forwarded: https://github.com/mbillingr/libgdf/pull/7
-Last-Update: 2021-07-07
-
---- libgdf-0.1.3.orig/libgdf/include/GDF/EventConverter.h
-+++ libgdf-0.1.3/libgdf/include/GDF/EventConverter.h
-@@ -32,7 +32,6 @@ namespace gdf
-     /// @throws general if events could not be converted
-     std::vector<Mode3Event> convertMode1EventsIntoMode3Events (std::vector<Mode1Event>
--                                                               const& mode_1_events)
--        throw (exception::general);
-+                                                               const& mode_1_events);
- }
- 
- #endif
---- libgdf-0.1.3.orig/libgdf/src/EventConverter.cpp
-+++ libgdf-0.1.3/libgdf/src/EventConverter.cpp
-@@ -34,7 +34,6 @@ namespace gdf
- 
-     //-------------------------------------------------------------------------
-     vector<Mode3Event> convertMode1EventsIntoMode3Events (vector<Mode1Event> const& mode_1_events)
--            throw (exception::general)
-     {
-         vector<Mode3Event> mode_3_events;
- 
diff --git a/debian/patches/disable-werror.patch b/debian/patches/disable-werror.patch
index c37b044..8dda033 100644
--- a/debian/patches/disable-werror.patch
+++ b/debian/patches/disable-werror.patch
@@ -8,8 +8,10 @@ Forwarded: not-needed
 Reviewed-By: Rafael Laboissiere <rafael@debian.org>
 Last-Update: 2019-08-16
 
---- libgdf-0.1.2.orig/libgdf/CMakeLists.txt
-+++ libgdf-0.1.2/libgdf/CMakeLists.txt
+Index: libgdf/libgdf/CMakeLists.txt
+===================================================================
+--- libgdf.orig/libgdf/CMakeLists.txt
++++ libgdf/libgdf/CMakeLists.txt
 @@ -2,9 +2,9 @@ cmake_minimum_required( VERSION 2.8 )
  project( GDF )
  
@@ -22,8 +24,10 @@ Last-Update: 2019-08-16
  elseif( WIN32 )
          add_definitions( -W3 )
          # Default Windows installs go to "C:\Program files" which may fail
---- libgdf-0.1.2.orig/test/CMakeLists.txt
-+++ libgdf-0.1.2/test/CMakeLists.txt
+Index: libgdf/test/CMakeLists.txt
+===================================================================
+--- libgdf.orig/test/CMakeLists.txt
++++ libgdf/test/CMakeLists.txt
 @@ -2,9 +2,9 @@ cmake_minimum_required( VERSION 2.8 )
  project( gdf_tests )
  
@@ -36,8 +40,10 @@ Last-Update: 2019-08-16
  elseif( WIN32 )
  	add_definitions( -W3 )
  endif( UNIX )
---- libgdf-0.1.2.orig/tools/gdf_merger/CMakeLists.txt
-+++ libgdf-0.1.2/tools/gdf_merger/CMakeLists.txt
+Index: libgdf/tools/gdf_merger/CMakeLists.txt
+===================================================================
+--- libgdf.orig/tools/gdf_merger/CMakeLists.txt
++++ libgdf/tools/gdf_merger/CMakeLists.txt
 @@ -2,9 +2,9 @@ cmake_minimum_required( VERSION 2.8 )
  project( gdf_merger )
  
diff --git a/debian/patches/series b/debian/patches/series
index d6aa771..a29cb00 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1 @@
 disable-werror.patch
-check-system-endianness.patch
-compile-with-g++-11.patch
diff --git a/distro/arch/PKGBUILD b/distro/arch/PKGBUILD
index 99bc7db..675133f 100644
--- a/distro/arch/PKGBUILD
+++ b/distro/arch/PKGBUILD
@@ -10,7 +10,7 @@ pkgrel=1
 epoch=
 pkgdesc="C++ implementation of GDF, the general dataformat for biosignals"
 arch=('i686' 'x86_64')
-url="http://sourceforge.net/projects/libgdf/"
+url="http://github.com/kazemakase/libgdf/"
 license=('LGPL')
 groups=()
 depends=(boost-libs)
@@ -28,7 +28,7 @@ source=()
 noextract=()
 md5sums=() #generate with 'makepkg -g'
 
-_gitroot='git://libgdf.git.sourceforge.net/gitroot/libgdf/libgdf'
+_gitroot='https://github.com/kazemakase/libgdf.git'
 _gitname='libgdf'
 
 build() {
diff --git a/libgdf/include/GDF/EventConverter.h b/libgdf/include/GDF/EventConverter.h
index c4e2f74..9a1ca6c 100644
--- a/libgdf/include/GDF/EventConverter.h
+++ b/libgdf/include/GDF/EventConverter.h
@@ -31,8 +31,7 @@ namespace gdf
     ///        using the flag 0x8000 which marks the type of mode 1 stop events
     /// @throws general if events could not be converted
     std::vector<Mode3Event> convertMode1EventsIntoMode3Events (std::vector<Mode1Event>
-                                                               const& mode_1_events)
-        throw (exception::general);
+                                                               const& mode_1_events);
 }
 
 #endif
diff --git a/libgdf/include/GDF/RecordBuffer.h b/libgdf/include/GDF/RecordBuffer.h
index fe3de7d..dfb1445 100644
--- a/libgdf/include/GDF/RecordBuffer.h
+++ b/libgdf/include/GDF/RecordBuffer.h
@@ -125,7 +125,7 @@ namespace gdf
         inline size_t getNumFullRecords( ) const { return m_num_full; }
 
         /// Get number of partially filled records currently in the list.
-        inline size_t getNumPartialRecords( ) const { return m_records.size( ); }
+        inline size_t getNumPartialRecords( ) const { return m_num_recs; }
 
         /// Returns reference to channel specified by channel_idx
         /** If channel does not exist gdf::nonexistent_channel_access::nonexistent_channel_access is thrown.
@@ -145,7 +145,7 @@ namespace gdf
         PointerPool<Record> *m_pool;
         std::list< Record* > m_records;
         std::list< Record* > m_records_full;
-        size_t m_num_full;
+        size_t m_num_full, m_num_recs;
         std::vector< std::list< Record* >::iterator > m_channelhead;
         std::list<RecordFullHandler*> m_recfull_callbacks;
     };
diff --git a/libgdf/include/GDF/TagHeader.h b/libgdf/include/GDF/TagHeader.h
index 50494fc..54d4daa 100644
--- a/libgdf/include/GDF/TagHeader.h
+++ b/libgdf/include/GDF/TagHeader.h
@@ -36,7 +36,7 @@ namespace gdf
     {
     public:
         /// Constructor
-        TagField( uint8 tag );
+        TagField( uint8 tag=0 );
 
         /// Destructor
         virtual ~TagField( );
diff --git a/libgdf/include/GDF/Types.h b/libgdf/include/GDF/Types.h
index ddaf742..c08fbac 100644
--- a/libgdf/include/GDF/Types.h
+++ b/libgdf/include/GDF/Types.h
@@ -21,7 +21,7 @@
 
 #include "Exceptions.h"
 #include <boost/cstdint.hpp>
-#include <boost/detail/endian.hpp>
+#include <boost/predef/other/endian.h>
 #include <iostream>
 
 namespace gdf
@@ -74,9 +74,9 @@ namespace gdf
     template<typename T>
     void writeLittleEndian( std::ostream &out, T item )
     {
-#if defined(BOOST_LITTLE_ENDIAN)
+#if BOOST_ENDIAN_LITTLE_BYTE
         out.write( reinterpret_cast<const char*>(&item), sizeof(item) );
-#elif defined(BOOST_BIG_ENDIAN)
+#elif BOOST_ENDIAN_BIG_BYTE
         const char* p = reinterpret_cast<const char*>(&item) + sizeof(item)-1;
         for( size_t i=0; i<sizeof(item); i++ )
             out.write( p--, 1 );
@@ -88,9 +88,9 @@ namespace gdf
     template<typename T>
     void readLittleEndian( std::istream &in, T &item )
     {
-#if defined(BOOST_LITTLE_ENDIAN)
+#if BOOST_ENDIAN_LITTLE_BYTE
         in.read( reinterpret_cast<char*>(&item), sizeof(item) );
-#elif defined(BOOST_BIG_ENDIAN)
+#elif BOOST_ENDIAN_BIG_BYTE
         char* p = reinterpret_cast<char*>(&item) + sizeof(item)-1;
         for( size_t i=0; i<sizeof(item); i++ )
     in.read( p--, 1 );
diff --git a/libgdf/include/GDF/Version.h b/libgdf/include/GDF/Version.h
index 68dbf46..9072733 100644
--- a/libgdf/include/GDF/Version.h
+++ b/libgdf/include/GDF/Version.h
@@ -21,7 +21,7 @@
 
 // Current library version
 // Must be the same as in the top level CMakeLists.txt
-#define GDF_VERSION "0.1.3"
+#define GDF_VERSION "0.1.4"
 
 
 #endif
diff --git a/libgdf/src/EventConverter.cpp b/libgdf/src/EventConverter.cpp
index 23b37f9..65d82a0 100644
--- a/libgdf/src/EventConverter.cpp
+++ b/libgdf/src/EventConverter.cpp
@@ -34,7 +34,6 @@ namespace gdf
 
     //-------------------------------------------------------------------------
     vector<Mode3Event> convertMode1EventsIntoMode3Events (vector<Mode1Event> const& mode_1_events)
-            throw (exception::general)
     {
         vector<Mode3Event> mode_3_events;
 
diff --git a/libgdf/src/EventDescriptor.cpp b/libgdf/src/EventDescriptor.cpp
index c9691ec..916c2e9 100644
--- a/libgdf/src/EventDescriptor.cpp
+++ b/libgdf/src/EventDescriptor.cpp
@@ -196,7 +196,7 @@ namespace gdf
         {
             desc = "";
             int i =0;
-            while( value[pos+i] != 0 && (pos+i < tagfieldlength)) {
+            while( (pos + i < tagfieldlength) && value[pos+i] != 0 ) {
                 desc.push_back(value[pos+i]);
                 i++;
             }
diff --git a/libgdf/src/EventHeader.cpp b/libgdf/src/EventHeader.cpp
index 1bd5047..b119d2f 100644
--- a/libgdf/src/EventHeader.cpp
+++ b/libgdf/src/EventHeader.cpp
@@ -18,6 +18,7 @@
 
 #include "GDF/EventHeader.h"
 #include "GDF/Exceptions.h"
+#include <math.h>
 #include <algorithm>
 #include <iostream>
 #include <sstream>
diff --git a/libgdf/src/GDFHeaderAccess.cpp b/libgdf/src/GDFHeaderAccess.cpp
index 9ebb2ca..14f5975 100644
--- a/libgdf/src/GDFHeaderAccess.cpp
+++ b/libgdf/src/GDFHeaderAccess.cpp
@@ -23,11 +23,6 @@
 #include <boost/numeric/conversion/cast.hpp>
 #include <list>
 #include <string>
-//#include <iostream>
-
-const double epsilon_d = 1e-15;
-const double epsilon_f = 1e-15;
-const double epsilon_i = 1;
 
 
 namespace gdf
@@ -403,6 +398,7 @@ namespace gdf
         hdr.getTagHeader_readonly( ).toStream( out );
         uint16 header3LenBlocks = mh->get_header_length() - (1+ns);
         assert( out.tellp() == std::streampos(256+256*ns+256*header3LenBlocks));
+        (void)header3LenBlocks; // To prevent -Werror=unused-variable in a release build.
 
         return out;
     }
@@ -417,8 +413,13 @@ namespace gdf
         MainHeader *mh = &hdr.m_mainhdr;
         mh->version_id.fromstream( in );
         int gdf_version_int = mh->getGdfVersionInt();
+#ifdef ALLOW_GDF_V_251
+        if (gdf_version_int < 210 || gdf_version_int > 251)
+#else
         if (gdf_version_int < 210 || gdf_version_int > 220)
+#endif
             throw exception::incompatible_gdf_version (mh->get_version_id ());
+
         mh->patient_id.fromstream( in );
         mh->reserved_1.fromstream( in );
         mh->patient_drugs.fromstream( in );
@@ -484,6 +485,12 @@ namespace gdf
                 {
                 case 0:
                     break;
+#ifdef ALLOW_GDF_V_251
+                default:
+                    evd.fromTagField(tagfield);
+                    taghdr.setEventDescriptor(evd);
+                    break;
+#else
                 case 1:
                     evd.fromTagField(tagfield);
                     taghdr.setEventDescriptor(evd);
@@ -491,6 +498,7 @@ namespace gdf
                 default:
                     throw exception::feature_not_implemented("Only tag==1 is supported in this build");
                     break;
+#endif
                 }
             }
             taghdr.setLength();
diff --git a/libgdf/src/Modifier.cpp b/libgdf/src/Modifier.cpp
index 368ce00..29ce76a 100644
--- a/libgdf/src/Modifier.cpp
+++ b/libgdf/src/Modifier.cpp
@@ -104,7 +104,7 @@ namespace gdf
             {
                 delete m_record_cache[i];
                 m_record_cache[i] = NULL;
-                m_record_changed[i] = NULL;
+                m_record_changed[i] = false;
             }
         }
     }
diff --git a/libgdf/src/Reader.cpp b/libgdf/src/Reader.cpp
index 0a310d1..9982625 100644
--- a/libgdf/src/Reader.cpp
+++ b/libgdf/src/Reader.cpp
@@ -67,8 +67,11 @@ namespace gdf
         {
             size_t samplesize = datatype_size( m_header.getSignalHeader_readonly( i ).get_datatype( ) );
             m_record_length += samplesize * m_header.getSignalHeader_readonly( i ).get_samples_per_record( );
-
+#ifdef ALLOW_GDF_V_251
+            double fs = m_header.getSignalHeader( i ).get_samples_per_record( );
+#else
             double fs = m_header.getSignalHeader( i ).get_samples_per_record( ) * m_header.getMainHeader_readonly().get_datarecord_duration(1) / m_header.getMainHeader_readonly().get_datarecord_duration(0);
+#endif
             m_header.getSignalHeader( i ).set_samplerate( boost::numeric_cast<uint32>(fs) );
         }
 
@@ -145,8 +148,11 @@ namespace gdf
         }
 
         buffer.resize( signal_indices.size() );
-
+#ifdef ALLOW_GDF_V_251
+        double record_rate = 1;
+#else
         double record_rate = m_header.getMainHeader_readonly().get_datarecord_duration(1) / m_header.getMainHeader_readonly().get_datarecord_duration(0);
+#endif
         size_t record = boost::numeric_cast<size_t>( floor( start_time * record_rate ) );
 
 
diff --git a/libgdf/src/RecordBuffer.cpp b/libgdf/src/RecordBuffer.cpp
index ccea519..6bc7d75 100644
--- a/libgdf/src/RecordBuffer.cpp
+++ b/libgdf/src/RecordBuffer.cpp
@@ -59,6 +59,7 @@ namespace gdf
         m_records.clear( );
         m_records_full.clear( );
 
+        m_num_recs = 0;
         m_num_full = 0;
     }
 
@@ -97,6 +98,7 @@ namespace gdf
         //std::cout << "Record Full" << std::endl;
         m_records_full.push_back( m_records.front() );
         m_records.pop_front( );
+        m_num_recs--;
         m_num_full++;
 
         // Sparse channels do not need m_channelhead[i] mechanism, but the mechanism
@@ -194,6 +196,7 @@ namespace gdf
         Record *r = m_pool->pop( );
         r->clear( );
         m_records.push_back( r );
+        m_num_recs++;
         std::list< Record* >::iterator it = m_records.end( );
         it--;
         return it;
@@ -230,26 +233,26 @@ namespace gdf
 
         if( m_channelhead[channel_idx] == m_records.end() )
         {
-            if( m_records.size() > 0 )
+            if( m_num_recs > 0 )
             {
                 if( m_records.back()->getChannel(channel_idx)->getFree( ) == 0 )
-				{
-					// Create a new record in m_records and inform all 
-					// channels that are pointing beyond the end m_records.
-
-					// capture the iter value that flags m_channelhead's that have no free space
-					std::list< Record* >::iterator end_iter = m_records.end();  
-					// get a clean record from m_pool, enlist it on m_records, and return an iterator
-					std::list< Record* >::iterator newrec_iter = createNewRecord( );
-					// broadcast the new record among all channels that need it
-					for( size_t i=0; i<m_channelhead.size(); i++ )
-					{
-						if (m_channelhead[i] == end_iter) 
-						{
-							m_channelhead[i] = newrec_iter;
-						}
-					}
-				}
+                {
+                    // Create a new record in m_records and inform all
+                    // channels that are pointing beyond the end m_records.
+
+                    // capture the iter value that flags m_channelhead's that have no free space
+                    std::list< Record* >::iterator end_iter = m_records.end();
+                    // get a clean record from m_pool, enlist it on m_records, and return an iterator
+                    std::list< Record* >::iterator newrec_iter = createNewRecord( );
+                    // broadcast the new record among all channels that need it
+                    for( size_t i=0; i<m_channelhead.size(); i++ )
+                    {
+                        if (m_channelhead[i] == end_iter)
+                        {
+                            m_channelhead[i] = newrec_iter;
+                        }
+                    }
+                }
                 else
                     throw exception::corrupt_recordbuffer( "DOOM is upon us!" );
             }
diff --git a/libgdf/src/TagHeader.cpp b/libgdf/src/TagHeader.cpp
index e836c13..a1ef6fd 100644
--- a/libgdf/src/TagHeader.cpp
+++ b/libgdf/src/TagHeader.cpp
@@ -56,6 +56,22 @@ namespace gdf
             gdf::TagField tagfield(0);
             tagfield.fromStream(stream); 
             tag = tagfield.getTagNumber();
+#ifdef ALLOW_GDF_V_251
+            if (tag == 0)
+            {
+                // Zero tag value indicates end of Header 3. See first row of Table 10 in GDF standard.
+                header3unpaddedsize += 1;
+            }
+            else if (1 <= tag && tag <= 13)
+            {
+                header3unpaddedsize += tagfield.getLength();
+                this->addTagField( tagfield );
+            }
+            else
+            {
+                throw exception::feature_not_implemented("Only tag==1..13 are supported in this build");
+            }
+#else
             switch( tag )
             {
             case 0:
@@ -70,6 +86,7 @@ namespace gdf
                 throw exception::feature_not_implemented("Only tag==1 is supported in this build");
                 break;
             }
+#endif
         }
         // consume the padding bytes that make Header 3 a multiple of 256 bytes
         size_t ns = hdr.getMainHeader_readonly().get_num_signals( );
@@ -185,7 +202,7 @@ namespace gdf
     //===================================================================================================
     //===================================================================================================
 
-    TagField::TagField( uint8 tag=0 ) : m_tag(tag)
+    TagField::TagField( uint8 tag ) : m_tag(tag)
     {
         ;
     }
@@ -233,4 +250,5 @@ namespace gdf
         for( size_t i=0; i<taglength; i++ )
             stream.read( reinterpret_cast<char*>(&m_value[i+4]), 1 );
     }
-}
\ No newline at end of file
+}
+
diff --git a/matlab/matlab_tools/Commands.h b/matlab/matlab_tools/Commands.h
index e836e1d..cabb59b 100644
--- a/matlab/matlab_tools/Commands.h
+++ b/matlab/matlab_tools/Commands.h
@@ -16,6 +16,7 @@
 #ifndef __COMMANDS_H_INCLUDED__
 #define __COMMANDS_H_INCLUDED__
 
+#include <map>
 #include <stdexcept>
 #include <string>
 #include "mex.h"
@@ -49,6 +50,7 @@ class CommandManager
 public:
     CommandManager( )
     {
+        default_cmd = NULL;
     }
 
     virtual ~CommandManager( )
@@ -58,6 +60,14 @@ public:
             delete it->second;
     }
 
+    void setDefaultCommand( const std::string cmdstr )
+    {
+        std::map< std::string, Command* >::iterator it = commands.find( toUpper( cmdstr ) );
+        if( it == commands.end() )
+            throw std::invalid_argument( "Invalid command: "+toUpper( cmdstr ) );
+        default_cmd = it->second;
+    }
+
     void registerCommand( const std::string cmdstr, Command * cmd, size_t nlhs, size_t nrhs )
     {
         cmd->setNP( nlhs, nrhs );
@@ -72,6 +82,13 @@ public:
         (*it->second)( nlhs, plhs, nrhs, prhs );
     }
 
+    void execute( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
+    {
+        if( !default_cmd )
+            throw std::invalid_argument( "No default command specified." );
+        (*default_cmd)( nlhs, plhs, nrhs, prhs );
+    }
+
     static std::string toUpper( const std::string str )
     {
             std::string out( str );
@@ -84,6 +101,7 @@ public:
 
 private:
     std::map< std::string, Command* > commands;
+    Command *default_cmd;
 };
 
 #endif // COMMANDS_H
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f541b8b..3ca8be1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -36,6 +36,10 @@ add_executable( testRWConsistency testRWConsistency.cpp )
 target_link_libraries( testRWConsistency ${Boost_LIBRARIES} GDF )
 add_test( NAME testRWConsistency COMMAND testRWConsistency )
 
+add_executable( testBlit testBlit.cpp )
+target_link_libraries( testBlit ${Boost_LIBRARIES} GDF )
+add_test( NAME testBlit COMMAND testBlit )
+
 add_executable( testSparseSampling testSparseSampling.cpp )
 target_link_libraries( testSparseSampling ${Boost_LIBRARIES} GDF )
 add_test( NAME testSparseSampling COMMAND testSparseSampling )
diff --git a/test/testBlit.cpp b/test/testBlit.cpp
new file mode 100644
index 0000000..2e0c8d4
--- /dev/null
+++ b/test/testBlit.cpp
@@ -0,0 +1,214 @@
+//
+// This file is part of libGDF.
+//
+// libGDF is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of
+// the License, or (at your option) any later version.
+//
+// libGDF is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with libGDF.  If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright 2010, 2013 Martin Billinger, Owen Kelly
+
+
+#include "config-tests.h"
+
+#include <GDF/Writer.h>
+#include <GDF/Reader.h>
+#include <GDF/TagHeader.h>
+#include <GDF/EventDescriptor.h>
+
+#include <iostream>
+#include <stdio.h>
+#include <sys/stat.h>
+
+using namespace std;
+
+const string testfile = "test.gdf.tmp";
+const string reffile0 = string(GDF_SOURCE_ROOT)+"/sampledata/MI128.gdf";
+const string annotfile = string(GDF_SOURCE_ROOT)+"/sampledata/Header3Tag1.gdf";
+const string alltypesfile = string(GDF_SOURCE_ROOT)+"/sampledata/alltypes.gdf";
+const string eventcodefile = string(GDF_SOURCE_ROOT)+"/libgdf/eventcodes.txt";
+
+bool fexist( std::string filename )
+{
+    std::ifstream f( filename.c_str(), std::ios_base::in );
+    if( f.fail() )
+        return false;
+    f.close( );
+    return true;
+}
+
+size_t fsize( std::string filename )
+{
+    struct stat filestatus;
+    stat( filename.c_str(), &filestatus );
+    return filestatus.st_size;
+}
+
+bool fcompare( std::string fileA, std::string fileB )
+{
+    std::ifstream f1( fileA.c_str(), std::ios_base::in | std::ios_base::binary );
+    std::ifstream f2( fileB.c_str(), std::ios_base::in | std::ios_base::binary );
+
+    bool state = true;
+
+    size_t ofs = 0;
+    while( !( f1.eof() || f2.eof() ) )
+    {
+        signed char a, b;
+        f1 >> a;
+        f2 >> b;
+
+
+        if( abs(a-b) > 1 )  // tolerate a difference of 1 due to rounding errors in digitial -> physical -> digital conversion
+        {
+            cout << ofs << " : " << (int)a << " ... " << (int)b << endl;
+            state = false;
+        }
+
+        ofs++;
+
+    }
+    return state;
+}
+
+int main( )
+{
+    std::vector<string> infilelist; // a list of files on which to run tests
+    infilelist.push_back(annotfile);
+    infilelist.push_back(alltypesfile);
+    infilelist.push_back(reffile0);
+
+    string reffile;
+
+
+    try
+    {
+        for(size_t file_count=0; file_count < infilelist.size(); file_count++)
+        {
+            reffile = infilelist[file_count]; // file to be tested in this loop iteration
+
+            cout << "Creating Writer instance." << endl;
+            gdf::Writer w;
+
+            cout << "Creating Reader instance." << endl;
+            gdf::Reader r;
+
+            r.enableCache( false );
+
+            cout << "Opening '" << reffile << "' for reading." << endl;
+            r.open( reffile );
+
+            cout << "Copying Header information." << endl;
+            w.getMainHeader( ).copyFrom( r.getMainHeader_readonly() );
+            w.getHeaderAccess().setRecordDuration( r.getMainHeader_readonly().get_datarecord_duration( 0 ), r.getMainHeader_readonly().get_datarecord_duration( 1 ) );
+            for( size_t m=0; m<w.getMainHeader_readonly().get_num_signals(); m++ )
+            {
+                w.createSignal( m, true );
+                w.getSignalHeader( m ).copyFrom( r.getSignalHeader_readonly( m ) );
+            }
+
+            w.setEventMode( r.getEventHeader()->getMode() );
+            w.setEventSamplingRate( r.getEventHeader()->getSamplingRate() );
+            // Copy GDF header 3 including user-specific event description table
+            gdf::TagHeader ath = r.getHeaderAccess_readonly().getTagHeader_readonly();
+            w.getHeaderAccess().getTagHeader().copyFrom( ath );
+
+            cout << "Opening '" << testfile << "' for writing." << endl;
+            w.open( testfile, gdf::writer_ev_memory | gdf::writer_overwrite );
+
+            cout << "Copying data .... ";
+
+            //size_t num_recs = boost::numeric_cast<size_t>( r.getMainHeader_readonly( ).get_num_datarecords( ) );
+            //for( size_t n=0; n<num_recs; n++ )
+            //{
+            //    gdf::Record *rec = w.acquireRecord( );
+            //    r.readRecord( n, rec );
+            //    w.addRecord( rec );
+            //}
+
+            std::vector< std::vector< double > > buffer;
+            r.getSignals(buffer);
+
+            for( size_t ch=0; ch<buffer.size(); ch++)
+            {
+                cout << ch << endl;
+                w.blitSamplesPhys(ch, buffer[ch]);
+            }
+
+            cout << "OK" << endl;
+
+            cout << "Copying events .... ";
+            gdf::EventHeader* ev_header = r.getEventHeader();
+            unsigned int num_events = ev_header->getNumEvents();
+            switch( ev_header->getMode() )
+            {
+            default: throw(std::runtime_error("ERROR -- Invalid event mode!"));
+            case 1: {
+                gdf::Mode1Event ev;
+                for(unsigned int m = 0; m < num_events; m++)
+                {
+                    ev_header->getEvent(m, ev);
+                    w.addEvent(ev);
+                }
+                    } break;
+            case 3: {
+                gdf::Mode3Event ev;
+                double sample_physical_value;
+                double sample_time_sec;
+
+                // Copy all event from source file to target file.
+                // Mode 1 and 3 events are copied.
+                // Sparse samples are extracted to (time,phys) then stored again.
+                for(unsigned int mm = 0; mm < num_events; mm++)
+                {
+                    ev_header->getEvent(mm, ev);
+                    if( ev.type != 0x7fff ) {
+                        w.addEvent(ev);
+                    } else {
+                        r.eventToSample(sample_time_sec, sample_physical_value, ev);
+                        // At this point we have successfully decoded a sparse sample
+                        //     (sample_time_sec, sample_physical_value)    .
+                        w.sampleToEvent( sample_time_sec, sample_physical_value, ev.channel, ev );
+                        // At this point we have successfully encoded a sparse sample into an event.
+                        // Now write the event to file.
+                        w.addEvent( ev );
+                    }
+                }
+                    } break;
+            }
+
+            cout << "OK" << endl;
+
+            w.close( );
+            cout << "Comparing files .... ";
+            if( !fcompare( reffile, testfile ) )
+            {
+                cout << "Failed." << endl;
+                return 1;
+            }
+            cout << "OK" << endl;
+
+            cout << "Removing " << testfile << endl << endl;
+            remove( testfile.c_str() );
+        }
+        return 0;   // test succeeded
+    }
+    catch( std::exception &e )
+    {
+        std::cout << "Caught Exception: " << e.what( ) << endl;
+    }
+    catch( ... )
+    {
+        std::cout << "Caught Unknown Exception." << endl;
+    }
+
+    return 1;   // test failed
+}