Release the lock when set and close file descriptor if opened.

        :Parameters:
            #. verbose (bool): Whether to be verbose about errors when encountered
            #. raiseError (bool): Whether to raise error exception when encountered

        :Returns:
            #. result (boolean): Whether the lock is succesfully released.
            #. code (integer, Exception): Integer code indicating the reason how the
               lock was successfully or unsuccessfully released. When releasing the
               lock generates an error, this will be caught and returned in a message
               Exception code.

               *  0: Lock is not found, therefore successfully released
               *  1: Lock is found empty, therefore successfully released
               *  2: Lock is found owned by this locker and successfully released
               *  3: Lock is found owned by this locker and successfully released and locked file descriptor was successfully closed
               *  4: Lock is found owned by another locker, this locker has no permission to release it. Therefore unsuccessfully released
               *  Exception: Lock was not successfully released because of an unexpected error.
                  The error is caught and returned in this Exception. In this case
                  result is False.

def release_lock(self, verbose=VERBOSE, raiseError=RAISE_ERROR):
        """
        Release the lock when set and close file descriptor if opened.

        :Parameters:
            #. verbose (bool): Whether to be verbose about errors when encountered
            #. raiseError (bool): Whether to raise error exception when encountered

        :Returns:
            #. result (boolean): Whether the lock is succesfully released.
            #. code (integer, Exception): Integer code indicating the reason how the
               lock was successfully or unsuccessfully released. When releasing the
               lock generates an error, this will be caught and returned in a message
               Exception code.

               *  0: Lock is not found, therefore successfully released
               *  1: Lock is found empty, therefore successfully released
               *  2: Lock is found owned by this locker and successfully released
               *  3: Lock is found owned by this locker and successfully released and locked file descriptor was successfully closed
               *  4: Lock is found owned by another locker, this locker has no permission to release it. Therefore unsuccessfully released
               *  Exception: Lock was not successfully released because of an unexpected error.
                  The error is caught and returned in this Exception. In this case
                  result is False.

        """
        if not os.path.isfile(self.__lockPath):
            released = True
            code     = 0
        else:
            try:
                with open(self.__lockPath, 'rb') as fd:
                    lock = fd.readlines()
            except Exception as err:
                code     = Exception( "Unable to read release lock file '%s' (%s)"%(self.__lockPath,str(err)) )
                released = False
                if verbose: print(str(code))
                if raiseError: raise code
            else:
                if not len(lock):
                    code     = 1
                    released = True
                elif lock[0].rstrip() == self.__lockPass.encode():
                    try:
                        with open(self.__lockPath, 'wb') as f:
                            #f.write( ''.encode('utf-8') )
                            f.write( ''.encode() )
                            f.flush()
                            os.fsync(f.fileno())
                    except Exception as err:
                        released = False
                        code     = Exception( "Unable to write release lock file '%s' (%s)"%(self.__lockPath,str(err)) )
                        if verbose: print(str(code))
                        if raiseError: raise code
                    else:
                        released = True
                        code     = 2
                else:
                    code     = 4
                    released = False
        # close file descriptor if lock is released and descriptor is not None
        if released and self.__fd is not None:
            try:
                if not self.__fd.closed:
                    self.__fd.flush()
                    os.fsync(self.__fd.fileno())
                    self.__fd.close()
            except Exception as err:
                code = Exception( "Unable to close file descriptor of locked file '%s' (%s)"%(self.__filePath,str(err)) )
                if verbose: print(str(code))
                if raiseError: raise code
            else:
                code = 3
        # return
        return released, code