# md5 hash einer Datei berechnen



## Gamer123 (6. Februar 2008)

wie der Titel schon sagt möchte ich gern den md5 Hash einer Datei berechnen.
Hab im Internet leider nichts gefunden außer Programme die das für mich schon machen. wills aber selber in ein eigenes Programm einbauen

ab leibsten währe mir 

char hash[33];
hash=mache_md5_hash(Pfad zur Datei)

glaube zwar nicht das es sowas gibt, aber hoffe es gibt ne lösung die nicht sehr kompliziert ist

ich programiere mit Dev-C++
unter Windows
Vielen Dank schon mal im Vorraus


----------



## deepthroat (6. Februar 2008)

Hi.

Schau dir mal boost::md5 an.

Die Datei mußt du nur mit einem ifstream im binary Modus öffnen und an den Konstruktor übergeben. Auf der Seite ist ein Beispiel.

Die boost Bibliothek solltest du einfach über den Update Manager von Dev-C++ installieren können.

Gruß


----------



## Gamer123 (6. Februar 2008)

ok danke, ich versuchs mal


----------



## Gamer123 (19. März 2008)

ich weis das thema is schon etwas älter, aber ich bekomme es einfach nicht hin.

ich versteh nich genau was ich machen muss.

ich hab die boost gedownloadet
und in meinen Code das beispiel eingesetzt:

```
#include <iostream>
#include <fstream>
#include <boost/md5.hpp>

int main(int argc, char *argv[])
{
   std::cout << boost::md5("message").hex_str_value();

   boost::md5(std::ifstream("file.txt")).hex_str_value();
}
```

leider bekomme ich den fehler das die klasse boost::md5 keinen member hex_str_value_type besitzt:



> 9 C:\Dev-Cpp\Projekte\md5_2\main.cpp 'class boost::md5' has no member named 'hex_str_value_type'



hab ich etwas vergessen, bitte um hilfe


----------



## deepthroat (19. März 2008)

Hi.





Gamer123 hat gesagt.:


> ```
> #include <iostream>
> #include <fstream>
> #include <boost/md5.hpp>
> ...


Scheint als wäre das Beispiel auf der Seite etwas veraltet...

Probier's mal so
	
	
	



```
std::cout << boost::md5("message").digest().hex_str_value();
```
Gruß


----------



## Gamer123 (19. März 2008)

danke erstmal, der eine Fehler ist schonmal weg, jetzt kommen neue:



> 11 C:\Dev-Cpp\Projekte\md5_2\main.cpp invalid conversion from `void*' to `const char*'
> 11 C:\Dev-Cpp\Projekte\md5_2\main.cpp   initializing argument 1 of `boost::md5::md5(const char*)'
> 11 C:\Dev-Cpp\Projekte\md5_2\main.cpp 'class boost::md5' has no member named 'hex_str_value'



wobei auf den zweiten befehl hingewiesen wird.

wenn ich .digest(). mit reinschreibe kommen die Fehler:



> 11 C:\Dev-Cpp\Projekte\md5_2\main.cpp invalid conversion from `void*' to `const char*'
> 11 C:\Dev-Cpp\Projekte\md5_2\main.cpp 'class boost::md5' has no member named 'hex_str_value'


----------



## deepthroat (19. März 2008)

Gamer123 hat gesagt.:


> danke erstmal, der eine Fehler ist schonmal weg, jetzt kommen neue:


Wie sieht dein Code denn jetzt aus? Anscheinend hast du versucht einen void* als Parameter an den Konstruktor von boost::md5 zu übergeben?!

Gruß


----------



## Gamer123 (20. März 2008)

main code sieht jetzt so aus:


```
#include <iostream>
#include <fstream>
#include <boost/md5.hpp>

int main(int argc, char *argv[])
{
   std::cout << boost::md5("message").digest().hex_str_value();

   boost::md5(std::ifstream("file.txt")).hex_str_value();
}
```
wobei die Fehler auf dem 2. befehl angezeigt werden


----------



## deepthroat (20. März 2008)

Gamer123 hat gesagt.:


> main code sieht jetzt so aus:
> 
> 
> ```
> ...


Beim 2. Befehl mußt du natürlich auch .digest() einfügen. Ich dachte das wäre klar...

Dann kann an den Konstruktor nur eine nicht-konstante Referenz auf einen istream übergeben werden, was dazu führt, dass man keine temporären Objekte übergeben kann.


```
ifstream input("test.txt");

cout << boost::md5(input).digest().hex_str_value() << endl;
```
Gruß


----------



## Gamer123 (20. März 2008)

> wobei auf den zweiten befehl hingewiesen wird.
> 
> wenn ich .digest(). mit reinschreibe kommen die Fehler:
> 
> ...



soweit konnte ich es mir auch denken

--Edit--
hab mein fehler entdeckt:
im Beispiel stand



> boost::md5(std::ifstream("file.txt")).hex_str_value();



und es musste heisen



> std::cout<<boost::md5(std::ifstream("file.txt")).hex_str_value();



ich hab jetzt das problem das es sehr viele Linker Errors gibt
z.B.
  [Linker error] undefined reference to `boost::md5::md5(char const*)' 

was nu?


----------



## deepthroat (20. März 2008)

Gamer123 hat gesagt.:


> soweit konnte ich es mir auch denken


Dann hast du evtl. noch einen anderen Fehler gemacht. Geht es jetzt oder was kommen jetzt für Fehler?

Gruß


----------



## deepthroat (20. März 2008)

Gamer123 hat gesagt.:


> ich hab jetzt das problem das es sehr viele Linker Errors gibt
> z.B.
> [Linker error] undefined reference to `boost::md5::md5(char const*)'
> 
> was nu?


Du mußt die md5.cpp mit in das Projekt einbinden und dazulinken.  \edit: oder die Bibliothek - je nachdem was du installiert hast.

Gruß


----------



## Gamer123 (20. März 2008)

sry, ich steh grad auf der leitung

aber wo finde ich die md5.cpp und wie linke ich drauf, unter Projekt Optionen -> Parmeter?


----------



## deepthroat (20. März 2008)

Gamer123 hat gesagt.:


> sry, ich steh grad auf der leitung
> 
> aber wo finde ich die md5.cpp und wie linke ich drauf, unter Projekt Optionen -> Parmeter?


Ich wieß ja nicht was du runtergeladen hast. Aber die Datei wäre hier: http://www.garret.ru/~baranov/boost_md5/lib/md5/md5.cpp

Die mußt du nur in dein Projekt mit einfügen, kompiliert und gelinkt wird sie dann automatisch.

Gruß


----------



## Gamer123 (20. März 2008)

ich bekomm es einfach nich hin

ich hab umber die dev c++ updates boost geladen

dann von
http://sourceforge.net/project/showfiles.php?group_id=7586&package_id=8041

wenn ich die datei einbinde komme massig fehler


----------



## Gamer123 (25. März 2008)

hoffe ihr hattet alle ein schönes Osterfest,

zurück zu meinem Problem
ich komm nicht klar, wenn ich die md5.cpp einbinde kommen unmengen Fehler
z.B.


> 35 C:\Dev-Cpp\Projekte\md5_2\md5.cpp expected init-declarator before "uint8_t"



kann mir vllt jemand ein beispiel Projekt schicken, bitte


----------



## Gamer123 (27. März 2008)

kann mir keiner helfen

der aufbau meines Projektes:

main.cpp


```
#include <iostream>
#include <fstream>
#include <boost/md5.hpp>
#include <boost/md5.cpp>

using namespace std;

int main(int argc, char *argv[])
{
   cout << boost::md5("message").digest().hex_str_value() << endl;

   ifstream input("test.txt");
   cout << boost::md5(input).digest().hex_str_value() << endl;
   
   system("pause");
}
```

md5.cpp

```
#include <cstdio>  // sprintf, sscanf
#include <cassert>

namespace boost
{

namespace
{
    typedef md5::uint8_t uint8_t;
    typedef md5::uint32_t uint32_t;

    /*
        Pack/unpack between arrays of uint8_t and uint32_t in
        a platform-independent way. Size is a multiple of 4.
    */

    void pack(uint8_t* dst, const uint32_t* src, uint32_t size)
    {
        uint32_t i(0);
        uint32_t j(0);

        while (j < size)
        {
            dst[j+0] = static_cast<uint8_t>((src[i] >>  0) & 0xff);
            dst[j+1] = static_cast<uint8_t>((src[i] >>  8) & 0xff);
            dst[j+2] = static_cast<uint8_t>((src[i] >> 16) & 0xff);
            dst[j+3] = static_cast<uint8_t>((src[i] >> 24) & 0xff);

            ++i;

            j += 4;
        }
    }

    void unpack(uint32_t* dst, const uint8_t* src, uint32_t size)
    {
        uint32_t i(0);
        uint32_t j(0);

        while (j < size)
        {
            dst[i] =
                (static_cast<uint32_t>(src[j+0]) <<  0) |
                (static_cast<uint32_t>(src[j+1]) <<  8) |
                (static_cast<uint32_t>(src[j+2]) << 16) |
                (static_cast<uint32_t>(src[j+3]) << 24);

            ++i;

            j += 4;
        }
    }

    void* secure_memset(void* dst, int c, uint32_t size)
    {
        return memset(dst, c, size);
    }
}

md5::md5()
{
    init();
}

md5::~md5()
{
    // Zeroize sensitive information.
    secure_memset(the_buffer, 0, sizeof(the_buffer));
}

md5::md5(const char* a_str)
{
    init();

    update(a_str);
}

md5::md5(const void* a_data, uint32_t a_data_size)
{
    init();

    update(a_data, a_data_size);
}

md5::md5(std::istream& a_istream)
{
    init();

    update(a_istream);
}

md5::md5(std::istream& a_istream, uint32_t a_size)
{
    init();

    update(a_istream, a_size);
}

void md5::init()
{
    the_is_dirty = true;

    the_count[0] = 0;
    the_count[1] = 0;

    the_state[0] = 0x67452301;
    the_state[1] = 0xefcdab89;
    the_state[2] = 0x98badcfe;
    the_state[3] = 0x10325476;
}

void md5::update(const char* a_str)
{
    update(a_str, strlen(a_str));  // Optimization possible but not worth it.
}

void md5::update(const void* a_data, uint32_t a_data_size)
{
    // Continuation after finalization is not implemented.
    // It is easy to implement - see comments in digest().
    assert(the_is_dirty);

    if (a_data_size != 0)
        the_is_dirty = true;

    // Compute number of bytes mod 64.
    uint32_t buffer_index = static_cast<uint32_t>((the_count[0] >> 3) & 0x3f);

    // Update number of bits.
    the_count[0] += (static_cast<uint32_t>(a_data_size) << 3);
    if (the_count[0] < (static_cast<uint32_t>(a_data_size) << 3))
        ++the_count[1];

    the_count[1] += (static_cast<uint32_t>(a_data_size) >> 29);

    uint32_t buffer_space = 64-buffer_index;  // Remaining buffer space.

    uint32_t input_index;

    // Transform as many times as possible.
    if (a_data_size >= buffer_space)
    {
        memcpy(the_buffer+buffer_index, a_data, buffer_space);
        process_block(&the_buffer);

        for (input_index = buffer_space; input_index+63 < a_data_size; input_index += 64)
        {
            process_block(reinterpret_cast<const uint8_t (*)[64]>(
                reinterpret_cast<const uint8_t*>(a_data)+input_index));
        }

        buffer_index = 0;
    }
    else
    {
        input_index = 0;
    }

    // Buffer remaining input.
    memcpy(the_buffer+buffer_index, reinterpret_cast<
        const uint8_t*>(a_data)+input_index, a_data_size-input_index);
}

void md5::update(std::istream& a_istream)
{
    uint8_t buffer[1024];

    while (a_istream)
    {
        a_istream.read(reinterpret_cast<char*>(&buffer[0]), sizeof(buffer));

        update(buffer, a_istream.gcount());
    }
}

void md5::update(std::istream& a_istream, uint32_t a_size)
{
    // TODO
}

const md5::digest_type& md5::digest()
{
    if (the_is_dirty)
    {
        static const uint8_t padding[64] =
        {
            0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        };

        // Save number of bits.
        uint8_t saved_count[8];
        pack(saved_count, the_count, 8);

        // TODO: State and buffer must be saved here to make continuation possible.

        // Pad out to 56 mod 64.
        uint32_t index = static_cast<uint32_t>((the_count[0] >> 3) & 0x3f);
        uint32_t padding_size = (index < 56) ? (56 - index) : (120 - index);
        update(padding, padding_size);

        // Append size before padding.
        update(saved_count, 8);

        // Store state in digest.
        digest_type::value_type digest_value;
        pack(digest_value, the_state, sizeof(digest_type::value_type));
        the_digest.reset(digest_value);

        // TODO: State and buffer must be restored here to make continuation possible.

        the_is_dirty = false;
    }

    return the_digest;
}

void md5::digest_type::reset(const hex_str_value_type& a_hex_str_value)
{
    delete[] the_hex_str_value;

    the_hex_str_value = 0;

    assert(a_hex_str_value[sizeof(hex_str_value_type) - 1] == '\0');

    for (unsigned int i(0); i < sizeof(value_type); ++i)
    {
        unsigned int value;

        int n = sscanf(&a_hex_str_value[i*2], "%02x", &value);

        assert(n == 1 && value <= 0xff);

        the_value[i] = static_cast<uint8_t>(value);
    }
}

const md5::digest_type::hex_str_value_type& md5::digest_type::hex_str_value() const
{
    if (the_hex_str_value == 0)
    {
        // Note: Have to cast because 'new char[33]' returns 'char*', not 'char(*)[33]'.
        the_hex_str_value = reinterpret_cast<hex_str_value_type*>(new hex_str_value_type);

        for (unsigned int i(0); i < sizeof(value_type); ++i)
        {
            sprintf(&(*the_hex_str_value)[i*2], "%02x", the_value[i]);
        }

        (*the_hex_str_value)[sizeof(hex_str_value_type) - 1] = '\0';  // Not necessary after sprintf.
    }

    return (*the_hex_str_value);
}

namespace
{
    typedef md5::uint8_t uint8_t;
    typedef md5::uint32_t uint32_t;

    const uint32_t S11(7);
    const uint32_t S12(12);
    const uint32_t S13(17);
    const uint32_t S14(22);
    const uint32_t S21(5);
    const uint32_t S22(9);
    const uint32_t S23(14);
    const uint32_t S24(20);
    const uint32_t S31(4);
    const uint32_t S32(11);
    const uint32_t S33(16);
    const uint32_t S34(23);
    const uint32_t S41(6);
    const uint32_t S42(10);
    const uint32_t S43(15);
    const uint32_t S44(21);

    inline uint32_t rotate_left(uint32_t x, uint32_t n_bits) { return (x << n_bits) | (x >> (32-n_bits)); }

    /*
        Basic MD5 functions.
    */

    inline uint32_t F(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); }
    inline uint32_t G(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); }
    inline uint32_t H(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; }
    inline uint32_t I(uint32_t x, uint32_t y, uint32_t z) { return y ^ (x | ~z); }

    /*
        Transformations for rounds 1, 2, 3, and 4.
    */

    inline void FF(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t  s, uint32_t ac)
    {
        a += F(b, c, d) + x + ac;
        a = rotate_left(a, s) + b;
    }

    inline void GG(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
    {
        a += G(b, c, d) + x + ac;
        a = rotate_left(a, s) + b;
    }

    inline void HH(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
    {
        a += H(b, c, d) + x + ac;
        a = rotate_left(a, s) + b;
    }

    inline void II(uint32_t& a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac)
    {
        a += I(b, c, d) + x + ac;
        a = rotate_left(a, s) + b;
    }
}

void md5::process_block(const uint8_t (*a_block)[64])
{
    uint32_t a(the_state[0]);
    uint32_t b(the_state[1]);
    uint32_t c(the_state[2]);
    uint32_t d(the_state[3]);

    /*volatile*/ uint32_t x[16];

    unpack(x, reinterpret_cast<const uint8_t*>(a_block), 64);

    // Round 1.
    FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /*  1 */
    FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /*  2 */
    FF(c, d, a, b, x[ 2], S13, 0x242070db); /*  3 */
    FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /*  4 */
    FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /*  5 */
    FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /*  6 */
    FF(c, d, a, b, x[ 6], S13, 0xa8304613); /*  7 */
    FF(b, c, d, a, x[ 7], S14, 0xfd469501); /*  8 */
    FF(a, b, c, d, x[ 8], S11, 0x698098d8); /*  9 */
    FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
    FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */

    // Round 2.
    GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
    GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
    GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
    GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
    GG(d, a, b, c, x[10], S22,  0x2441453); /* 22 */
    GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
    GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
    GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
    GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
    GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
    GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */

    // Round 3.
    HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
    HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
    HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
    HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
    HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
    HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
    HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
    HH(b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
    HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
    HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */

    // Round 4.
    II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
    II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
    II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
    II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
    II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
    II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
    II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
    II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
    II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
    II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */

    the_state[0] += a;
    the_state[1] += b;
    the_state[2] += c;
    the_state[3] += d;

    // Zeroize sensitive information.
    secure_memset(reinterpret_cast<uint8_t*>(x), 0, sizeof(x));
}

}
```
md5.hpp

```
namespace boost
{
    class md5
    {
    public:
        md5();
        ~md5();

        // Constructs a digest for given message data.
        md5(const char* a_str);
        md5(const void* a_data, uint32_t a_data_size);
        md5(std::istream& a_istream);

        // Updates the digest with additional message data.
        void update(const char* a_str);
        void update(const void* a_data, uint32_t a_data_size);
        void update(std::istream& a_istream);

        // A message digest.
        class digest_type
        {
        public:
            // A digest value as a 16-byte raw binary array.
            typedef uint8_t value_type[16];

            // A digest value as a 33-byte ascii-hex string.
            typedef char hex_str_value_type[33];

            digest_type();  // Constructs a zero digest.
            digest_type(const value_type& a_value);
            digest_type(const hex_str_value_type& a_hex_str_value);
            digest_type(const digest_type& a);

            void reset();  // Resets to a zero digest.
            void reset(const value_type& a_value);
            void reset(const hex_str_value_type& a_hex_str_value);
            digest_type& operator=(const digest_type& a);

            // Gets the digest value.
            const value_type& value() const;
            const hex_str_value_type& hex_str_value() const;

            ~digest_type();
        };

        // Acquires the digest.
        const digest_type& digest();
    };

    inline bool operator==(const md5::digest_type& a, const md5::digest_type& b);
    inline bool operator!=(const md5::digest_type& a, const md5::digest_type& b);
}
```

und einige Fehler


> 9 C:\Dev-Cpp\include\boost\md5.cpp expected init-declarator before "uint8_t"
> 9 C:\Dev-Cpp\include\boost\md5.cpp expected `,' or `;' before "uint8_t"
> 62 C:\Dev-Cpp\include\boost\md5.cpp `init' undeclared (first use this function)
> 68 C:\Dev-Cpp\include\boost\md5.cpp `the_buffer' undeclared (first use this function)


uvm.
habe ich was vergessen zu includen, Hilfe


----------

