std::vector< CHashMatch > CDataBase::searchByHash_offs( CHash hash ) const {
    std::vector< CHashMatch > result;
    std::ifstream hash_file;
    std::vector< std::pair< uint64_t, int64_t > > matches; // vector of pairs ( mel_id, offset )

    // hash offset cycle
    for( int64_t fixed_hash_offset = 0; 
            fixed_hash_offset < static_cast< int64_t >( hash.getLength() ) - static_cast< int64_t >( CFixedHash::length ); 
            ++fixed_hash_offset ) {

        CFixedHash fixed_hash( hash, fixed_hash_offset );
        std::string hash_filename = makeFilenameOfHash( fixed_hash );
        hash_file.open( makeFilenameOfHash( fixed_hash ),
                        std::fstream::in | std::fstream::binary );
        if( ! hash_file.is_open() ) {
            std::cout << "ERROR: Couldn't open hash file for reading: " << hash_filename << '\n';
            return result;
        }

        // fixed hash file read cycle
        while( hash_file.is_open() && hash_file.good() && hash_file.peek() != EOF ) {
            // read melody id
            uint64_t mel_id = 0;
            Raspoznavayka::mel_size_t mel_chm_offs = 0;
            if( ! ( read_number_from_file( mel_id, mel_number_size_koeff, hash_file ) // read melody id
                 && read_number_from_file( mel_chm_offs, mel_max_size_koeff, hash_file ) // read fixed hash match offset in melody
                 ) ) {
                return result;
            }
            
            int64_t total_offset = static_cast<int64_t>( mel_chm_offs ) - static_cast<int64_t>( fixed_hash_offset );
            // check distinct
            bool found = false;
            for( auto i = matches.begin(); i != matches.end(); ++i ) {
                if( i->first == mel_id && i->second == total_offset ) {
                    found = true;
                    break;
                }
            }
            if( !found ) {
                // push to matches
                matches.push_back( std::pair< uint64_t, int64_t >( mel_id, total_offset ) );
            }
        } // end of fixed hash file read cycle

        hash_file.close();
    } // end of hash offset cycle

    // read found melodies' data
    std::ifstream index_file;
    std::ifstream id3_file;
    std::ifstream mel_file;
    index_file.open( index_filename, std::fstream::in | std::fstream::binary );
    id3_file.open( id3_filename, std::fstream::in );
    mel_file.open( mel_filename, std::fstream::in | std::fstream::binary );
    if( ! ( index_file.is_open() && id3_file.is_open() && mel_file.is_open() ) ) {
        std::cout << "ERROR: Couldn't open some DB file for writing in " << directory << '\n';
        return result;
    }

    for( auto match = matches.begin(); match != matches.end(); ++match ) {
        int64_t mel_id = match->first, total_offset = match->second;
        // get index entry on this song
        index_file.seekg( mel_id * ( mel_number_size_koeff + mel_file_max_size_koeff ) );
        // get id3 and and melody addresses
        uint64_t id3_start = 0, id3_end = 0, mel_start = 0, mel_end = 0;
        if( ! ( read_number_from_file( id3_start, id3_file_max_size_koeff, index_file )
             && read_number_from_file( mel_start, mel_file_max_size_koeff, index_file )
             && read_number_from_file( id3_end, id3_file_max_size_koeff, index_file )
             && read_number_from_file( mel_end, mel_file_max_size_koeff, index_file )
             ) ) {
            return result;
        }
        // read id3 tags
        assert( id3_start < id3_end );
        assert( mel_start < mel_end );
        std::string artist, album, name, year;
        uint64_t record_size = id3_end - id3_start;
        if( ! id3_file.seekg( id3_start ).good() ) {
            std::cout << "ERROR: in id3 file\n";
            break;
        }
        std::getline( id3_file, artist );
        record_size -= id3_file.gcount();
        std::getline( id3_file, album );
        record_size -= id3_file.gcount();
        std::getline( id3_file, name );
        record_size -= id3_file.gcount();
        std::getline( id3_file, year );
        if( ! mel_file.seekg( mel_start ).good() ) {
            std::cout << "ERROR: in mel file\n";
            break;
        }
        std::vector< Raspoznavayka::interval_t > intervals( mel_end - mel_start );
        for( uint64_t i = 0; i < mel_end - mel_start; ++i ) {
            char interval;
            if( mel_file.get( interval ).fail() ) {
                std::cout << "ERROR: in mel file\n";
                break;
            }
            intervals[i] = static_cast< Raspoznavayka::interval_t >( interval );
        }
        CIDTag idtag( artist, album, name, std::atoi( year.c_str() ) );
        CInDBMelody new_melody( intervals, idtag );
        CHashMatch new_chm( &new_melody, total_offset );
        result.push_back( new_chm );
    } // end of found melodies' data read cycle

    id3_file.close();
    mel_file.close();
    index_file.close();
    return result;
}