Changeset 22 in projects


Ignore:
Timestamp:
Oct 8, 2008, 1:12:22 AM (11 years ago)
Author:
sven
Message:

Great directory restructuring: The GtkPaperTape files are now splitted
up in their own directory and all using shorter names and labels:
PaperTape::Color in favour of GtkPaperTapeColor. Furthermore all files
are in revision progress, started a bit with zoom.h/zoom.cc and
greatly with file.h. Work still in progress -- this commit won't
compile at all!

Fixed a small bug in lochstreifen.c that caused crashing at repainting
because the callback function pointer was not initialized to NULL.

-- Sven @ workstation

Location:
visualisator
Files:
2 added
2 edited
1 copied
11 moved

Legend:

Unmodified
Added
Removed
  • visualisator/gtk.cc

    r19 r22  
    1919        loop.run(win);
    2020}
     21
     22
     23#include "gtkpapertape.h"
     24
     25int main(int argc, char** argv) {
     26        Main loop(argc, argv);
     27       
     28        PaperTape::Chrome win;
     29        win.set_app_name("Hello World Application");
     30       
     31        win.show();
     32        loop.run(win);
     33}
  • visualisator/lochstreifen.c

    r19 r22  
    6868        cairo_matrix_init(&l->matrix, 1, 0, 0, 1, 0, 0); // default = 1:1 original
    6969        l->matrix_inverse             = l->matrix;
     70        l->row_callback               = NULL;
     71        l->row_callback_user_data     = NULL;
    7072
    7173        return l;
     
    107109        l->matrix                     = template->matrix;
    108110        l->matrix_inverse             = template->matrix_inverse;
     111        l->row_callback               = template->row_callback;
     112        l->row_callback_user_data     = template->row_callback_user_data;
    109113
    110114        return l;
     
    115119 * *except* from the data. You have to manage them on your own.
    116120 * In the end, it will free the LOCHSTREIFEN itself.
     121 * This won't touch your row_callback_user_data.
    117122 * @return Nothing, because there's nothing left. Except your data, okay.
    118123 **/
     
    946951                // call row callback
    947952                if(l->row_callback != NULL) {
     953                        printf("CALLING ROW CALLBACK!\n");
    948954                        (*l->row_callback) (&row, cr, l->row_callback_user_data);
    949955                        // at least now that's all the magic ;)
     
    992998                        }
    993999                       
     1000                        printf("testing byte\n");
    9941001                        if( ((l->data[row] >> track) & 0x01) != 0x01) {
    9951002                                // bit is logical ZERO (0)
  • visualisator/papertape/file.cc

    r19 r22  
    5959                throw Glib::Error(err, true);
    6060        }
     61        std::cout << "Read in file " << filename << " successfully.\n";
    6162        data_changed.emit(data, data_len);
    62 /*
    63         if(ret == FALSE) {
    64                 GtkWidget *error;
    65                 error = gtk_message_dialog_new (GTK_WINDOW(papertape->parent_window),
    66                         GTK_DIALOG_DESTROY_WITH_PARENT,
    67                         GTK_MESSAGE_ERROR,
    68                         GTK_BUTTONS_OK,
    69                         "Error loading file '%s': %s",
    70                         filename, err->message);
    71                 gtk_dialog_run (GTK_DIALOG (error));
    72                 gtk_widget_destroy (error);
    73                 return FALSE;
    74         }
    75 
    76         papertape->name_of_file = g_path_get_basename(filename); // allocates new string
    77         papertape->file_opened = TRUE;
    78         gtk_window_set_title(GTK_WINDOW(papertape->parent_window), g_strdup_printf(
    79                         "%s - %s", papertape->window_base_title, papertape->name_of_file
    80                 ));
    81         gtk_paper_tape_set_data(papertape, length, (byte_t *)data);
    82         return TRUE;
    83         return true;
    84 */
    8563}
    8664
  • visualisator/papertape/file.h

    r19 r22  
    1 #ifndef __GTK_PAPER_TAPE_MODEL_H__
    2 #define __GTK_PAPER_TAPE_MODEL_H__
     1#ifndef __PAPER_TAPE_FILE_H__
     2#define __PAPER_TAPE_FILE_H__
     3
     4/* $Id$ */
     5
     6/* visualisation/papertape/file.h
     7 *
     8 * Copyright (C) 2008 Sven Koeppel
     9 *
     10 * This library is free software; you can redistribute it and/or
     11 * modify it under the terms of the GNU Library General Public
     12 * License as published by the Free Software Foundation; either
     13 * version 2 of the License, or (at your option) any later version.
     14 *
     15 * This library is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 * Library General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU Library General Public
     21 * License along with this library; if not, write to the Free
     22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     23 */
    324
    425#include <string>
    526
    6 namespace Gtk
    7 { class PaperTapeFile; }
    8 #include "lochstreifen.h"
    9 #include "gtkpapertape.h"
    10 
    11 namespace Gtk {
     27namespace PaperTape
     28{ class File; }
     29#include "../lochstreifen.h"
     30#include "view.h"
     31
     32namespace PaperTape {
    1233
    1334/**
    14  * The PaperTapeFile class represents an opened Paper Tape File. This
    15  * is the "model" class in the GtkPaperTape MVC concept.
    16  *
    17  * The class holds the binary data from the file and performs modifications
    18  * to these data. It features a signal (sigc++) that is fired whenever the
    19  * data array is changed.
    20  *
     35 * The File class hold the contents of a file (always completely in RAM).
     36 * This is the "model" class in the PaerTape concept. This class a nice
     37 * interface with many handy methods, even GTK dialogs for opening/closing/....
     38 *
     39 * The class doesn't hold instances of View or Chrome. For proper dialog
     40 * working, you are encouraged to use set_parent_window(Gtk::Window) or
     41 * the appropriate constructor.
     42 *
     43 * This class uses sigc++ signals that are fired whenever the internal binary
     44 * data array is changed.
     45 *
     46 * Compared to the Gtk+ text widget system, this class is comparable to the
     47 * GtkTextBuffer. Therefore there's the nested iterator, working like GtkTextIter.
    2148 *
    2249 **/
    23 class PaperTapeFile {
     50class File {
    2451        PaperTape *controller;
    2552
     
    3461
    3562        PaperTapeFile(PaperTape* controller);
     63       
     64        // the nested iterator class
     65        class iterator;
     66        friend class iterator;
     67       
     68        /**
     69         * This iterator shall feel like a row_t, which is an int typedef,
     70         * so this iterator shall feel like an int. There's not much overhead
     71         * when creating it on run time with the File utility methods.
     72         * It acts and feels like any ordinary C++ iterator.
     73         *
     74         **/
     75        class iterator {
     76                bool backward_byte();
     77                bool backward_bytes(int count);
     78                bool backward_search(byte_t value);
     79                bool backward_search(byte_t value, const iterator& limit);
     80                bool backward_visible_byte(); // viewport (scrolling!)
     81                int compare(const iterator& rhs) const;
     82                // like operator>: returns negative if lhs is less than rhs, positive if lhs is greater than rhs, and 0 if they're equal.
     83               
     84                bool forward_byte();
     85                bool forward_bytes(int count);
     86                bool forward_search(byte_t value);
     87                bool forward_visible_byte();
     88                bool forward_to_end(); // to end of file
     89
     90                // getters
     91                File& get_file() const; // returns the associated file
     92                byte_t get_byte() const; // returns the byte which the iterator is on.
     93                int get_pos() const; // returns position from 0 in the file
     94                int get_visible_pos() const; // returns position from viewport
     95               
     96                bool in_range(const TextIter& start, const TextIter& end) const; // wheter iter falls in range [start, end[
     97                bool is_cursor_position() const;
     98                bool is_end() const;
     99                bool is_start();       
     100
     101                iterator& operator++() { forward_char(); return *this;  }
     102                iterator& operator--() { backward_char(); return *this; }
     103
     104                // auch intelligent:
     105                // void order(iterator& second) // swaps the value of first and second if second comes before first in file
     106
     107                // setters
     108                void set_byte(row_t row_number); // if row_number > file size => at end of file
     109        }
    36110
    37111        // hier auch Funktionen zum LABEL
     
    52126        //void pop_bytes
    53127        // etc.
     128       
     129        // clipboard interaction
     130        void cut_clipboard(const Glib::RefPtr<Clipboard>& clipboard);
     131        void copy_clipboard(const Glib::RefPtr<Clipboard>& clipboard);
     132        void paste_clipboard(const Glib::RefPtr<Clipboard>& clipboard); // at current position
     133        void paste_clipboard(const Glib::RefPtr<Clipboard>& clipboard, const iterator& override_location);
     134       
     135        // getting iterators
     136        iterator start();
     137        iterator end();
     138        iterator get_cursor();
     139       
     140        erase(const iterator& range_begin, const iterator& range_end);
     141        erase_selection(); // delete current selection
     142       
     143        bool has_selection();
     144       
    54145
    55146        // interne Low Level Funktionen.
    56147        // (intern = Gtk::PaperTape)
    57148        void set(byte_t* data, int data_len);
     149        byte_t* get(iterator& start, iterator& end); // get a range. this WON'T COPY data, just data[start].
     150       
    58151        void add_null_bytes(int start, int end);
    59152       
     
    63156        void open();
    64157       
    65         /// open that file.
     158        /// Whether the file was modified since the last set_modified call
     159        bool get_modified();
     160        /// "Brute force" change the modification state. Not supposed to be used
     161        /// (save() calls it itself).
     162        void set_modified(bool setting);
     163       
     164        /// open that file (non GUI)
    66165        /// @throws GError if an error occurred
    67166        void open(const std::string& filename);
     
    127226
    128227}; // Namespace Gtk
    129 #endif // __GTK_PAPER_TAPE_MODEL_H
     228#endif // __PAPER_TAPE_FILE_H
  • visualisator/papertape/view.h

    r19 r22  
    1 #ifndef __GTK_PAPER_TAPE_VIEW__
    2 #define __GTK_PAPER_TAPE_VIEW__
     1#ifndef __PAPER_TAPE_VIEW__
     2#define __PAPER_TAPE_VIEW__
    33
    44#include <gtkmm/drawingarea.h>
     
    1111namespace Gtk
    1212{ class PaperTapeView; }
    13 #include "gtkpapertape.h"
    14 #include "lochstreifen.h"
    15 #include "gtkpapertapecolor.h"
    16 #include "gtkpapertapezoom.h"
     13#include "view.h"
     14#include "../lochstreifen.h"
     15#include "color.h"
     16#include "zoom.h"
    1717
    18 namespace Gtk {
     18namespace PaperTape {
    1919
    2020/**
     
    4343 *
    4444 **/
    45 class PaperTapeView : public DrawingArea {
     45class View : public Gtk::DrawingArea {
    4646public:
    47         std::map<std::string, Glib::RefPtr<PaperTapeColor> > colors;
     47        std::map<std::string, Glib::RefPtr<PaperTape::Color> > colors;
    4848        void add_color(
    4949                const Glib::ustring& name,
     
    5454        );
    5555       
    56         Gtk::PaperTapeZoom* zoom; // must be link for compiling issues :/
     56        PaperTape::Zoom* zoom; // must be link for compiling issues :/
    5757       
    5858private:       
     
    7171         * to. It won't change in the PaperTapeView life time.
    7272         **/
    73         PaperTape* const controller;
     73        Chrome* const controller;
     74       
    7475        /**
    7576         * Each View has it's own LOCHSTREIFEN object and therefore it's own
     
    9394
    9495public:
    95         PaperTapeView(PaperTape* controller);
     96        //View(Chrome* controller);
     97        View(File* file);
    9698       
    9799        virtual bool on_expose_event(GdkEventExpose *event);
     
    138140
    139141}; // namespace Gtk
    140 #endif // __GTK_PAPER_TAPE_VIEW__
     142#endif // __PAPER_TAPE_VIEW__
  • visualisator/papertape/zoom.cc

    r20 r22  
    1 #include "gtkpapertapezoom.h"
     1/* visualisation/papertape/zoom.cc
     2 * The Paper Tape Project -- Visualisation
     3 * (c) Copyright 2008 Sven Köppel
     4 *
     5 * This program is free software; you can redistribute
     6 * it and/or modify it under the terms of the GNU General
     7 * Public License as published by the Free Software
     8 * Foundation; either version 3 of the License, or (at
     9 * your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will
     12 * be useful, but WITHOUT ANY WARRANTY; without even the
     13 * implied warranty of MERCHANTABILITY or FITNESS FOR A
     14 * PARTICULAR PURPOSE. See the GNU General Public License
     15 * for more details.
     16 *
     17 * You should have received a copy of the GNU General
     18 * Public License along with this program; if not, see
     19 * http://www.gnu.org/licenses/
     20 */
     21
     22#include "zoom.h"
     23
    224#include <gtkmm/actiongroup.h>
    325#include <gtkmm/table.h>
     
    1436using namespace Gtk;
    1537
    16 
    1738/* { name, stock_id, label, acclerator, tooltip, callback } */
    18 GtkActionEntry PaperTapeZoom::ui_action_entries[] = {
     39GtkActionEntry PaperTape::Zoom::ui_action_entries[] = {
    1940        { "ZoomIn", GTK_STOCK_ZOOM_IN },
    2041        { "ZoomOut", GTK_STOCK_ZOOM_OUT },
     
    3253};
    3354
    34 PaperTapeZoom::PaperTapeZoom(double default_rotation, double default_zoom_factor, PaperTapeFlip default_flip) {
     55PaperTape::Zoom::Zoom(double default_rotation, double default_zoom_factor, PaperTapeFlip default_flip) {
    3556        // init values
    3657        this->rotation = default_rotation;
     
    4162}
    4263
    43 void PaperTapeZoom::show_dialog() {
     64void PaperTape::Zoom::show_dialog() {
    4465        if(!matrix_dialog) {
    4566                // set up the matrix_dialog.
     
    5172                // connect matrix_manually button
    5273                matrix_manually->signal_toggled().connect(
    53                         sigc::bind(sigc::mem_fun(*this, &PaperTapeZoom::on_toggle_manually), matrix_manually)
     74                        sigc::bind(sigc::mem_fun(*this, &PaperTape::Zoom::on_toggle_manually), matrix_manually)
    5475                );
    5576                matrix_frame->set_label_widget(*matrix_manually);
     
    91112                        i->second->signal_value_changed().connect(
    92113                                sigc::bind(
    93                                         sigc::mem_fun(*this, &PaperTapeZoom::on_change_field),
     114                                        sigc::mem_fun(*this, &PaperTape::Zoom::on_change_field),
    94115                                        i->first
    95116                                )
     
    106127                matrix_dialog->get_action_area()->add(*reset);
    107128                matrix_dialog->get_action_area()->set_child_secondary(*reset);
    108                 reset->signal_clicked().connect(sigc::mem_fun(*this, &PaperTapeZoom::reset));
     129                reset->signal_clicked().connect(sigc::mem_fun(*this, &PaperTape::Zoom::reset));
    109130
    110131                //matrix_dialog->add_button(Stock::APPLY, 2);
     
    118139               
    119140                // update the entry things whenever the zoom is changed
    120                 this->signal_changed().connect(sigc::mem_fun(*this, &PaperTapeZoom::update_dialog_on_zoom_changes));
     141                this->signal_changed().connect(sigc::mem_fun(*this, &PaperTape::Zoom::update_dialog_on_zoom_changes));
    121142               
    122143                //matrix_dialog->add(*main_box);
     
    131152}
    132153
    133 void PaperTapeZoom::update_dialog_on_zoom_changes() {
     154void PaperTape::Zoom::update_dialog_on_zoom_changes() {
    134155        for(std::map<double*, SpinButton*>::iterator i = matrix_entries.begin();
    135156            i != matrix_entries.end(); i++) {
     
    138159}
    139160
    140 void PaperTapeZoom::reset() {
     161void PaperTape::Zoom::reset() {
    141162        if(this->is_controlled_manually()) {
    142163                *this = default_matrix; /*xx = default_matrix.xx; xy = default_matrix.xy; x0 = default_matrix.x0;
     
    150171}
    151172
    152 void PaperTapeZoom::on_toggle_manually(CheckButton* manually_toggle) {
     173void PaperTape::Zoom::on_toggle_manually(CheckButton* manually_toggle) {
    153174        this->manually = manually_toggle->get_active();
    154175        // turn input widgets on/off
     
    160181}
    161182
    162 void PaperTapeZoom::on_change_field(double* field) {
     183void PaperTape::Zoom::on_change_field(double* field) {
    163184        // only for internal use
    164185        if(!field) {
     
    174195}
    175196
    176 void PaperTapeZoom::calc_matrix() {
     197void PaperTape::Zoom::calc_matrix() {
    177198        // take the buffer things and calculate a new matrix, FROM
    178199        // DEFAULT MATRIX.
     
    186207}
    187208
    188 void PaperTapeZoom::set_default(double rotation, double zoom_factor, PaperTapeFlip flip) {
     209void PaperTape::Zoom::set_default(double rotation, double zoom_factor, PaperTape::Flip flip) {
    189210        // change default matrix.
    190211        cairo_matrix_init_identity(&this->default_matrix);
     
    194215}
    195216
    196 void PaperTapeZoom::set_rotate(double radians, bool relative) {
     217void PaperTape::Zoom::set_rotate(double radians, bool relative) {
    197218        if(!is_controlled_manually()) {
    198219                this->rotation = relative ? (this->rotation + radians) : radians;
     
    205226}
    206227
    207 void PaperTapeZoom::set_zoom(double zoom_factor, bool relative) {
     228void PaperTape::Zoom::set_zoom(double zoom_factor, bool relative) {
    208229        if(!is_controlled_manually()) {
    209230                this->zoom_factor = relative ? (this->zoom_factor * zoom_factor) : zoom_factor;
     
    216237}
    217238
    218 void PaperTapeZoom::set_flip(PaperTapeFlip flip, bool relative) {
     239void PaperTape::Zoom::set_flip(PaperTape::Flip flip, bool relative) {
    219240        // not implemented yet
    220241}
    221242
    222 Glib::RefPtr<ActionGroup> PaperTapeZoom::get_action_group() {
    223         Glib::RefPtr<ActionGroup> group = ActionGroup::create("GtkPaperTapeZoom");
     243Glib::RefPtr<ActionGroup> PaperTape::Zoom::get_action_group() {
     244        Glib::RefPtr<ActionGroup> group = ActionGroup::create("PaperTapeZoom");
    224245       
    225246        gtk_action_group_add_actions(
     
    229250                        NULL);
    230251
    231         group->signal_post_activate().connect(sigc::mem_fun(*this, &PaperTapeZoom::transform_action));
     252        group->signal_post_activate().connect(sigc::mem_fun(*this, &PaperTape::Zoom::transform_action));
    232253
    233254        return group;
    234255}
    235256
    236 void PaperTapeZoom::transform_action(const Glib::RefPtr<Action>& action) {
     257void PaperTape::Zoom::transform_action(const Glib::RefPtr<Action>& action) {
    237258        Glib::ustring name = action->get_name();
    238259       
     
    268289                // same here...
    269290        } else {
    270                 std::cout << "PaperTapeZoom: Action " << name << " not supported!\n";
    271         }
    272 }
    273 
    274 void PaperTapeZoom::set_auto_zoom(PaperTapeView& view, PaperTapeAutoZoomType type) {
     291                std::cout << "PaperTape::Zoom: Action " << name << " not supported!\n";
     292        }
     293}
     294
     295void PaperTape::Zoom::set_auto_zoom(PaperTape::View& view, PaperTape::AutoZoomType type) {
    275296        this->auto_zoom_enabled = true;
    276297
    277298        // connect resize signal
    278299        auto_zoom_resize_con = view.signal_configure_event().connect(
    279                 sigc::mem_fun(*this, &PaperTapeZoom::on_auto_zoom_resize)
     300                sigc::mem_fun(*this, &PaperTape::Zoom::on_auto_zoom_resize)
    280301        );
    281302
     
    284305}
    285306
    286 void PaperTapeZoom::disable_auto_zoom() {
     307void PaperTape::Zoom::disable_auto_zoom() {
    287308        if(auto_zoom_enabled) {
    288309                auto_zoom_resize_con.disconnect();
     
    291312}
    292313
    293 bool PaperTapeZoom::on_auto_zoom_resize(GdkEventConfigure* event) {
     314bool PaperTape::Zoom::on_auto_zoom_resize(GdkEventConfigure* event) {
    294315        // depending on orientation, use event->width and event->height
    295316       
  • visualisator/papertape/zoom.h

    r19 r22  
    1 #ifndef __GTK_PAPER_TAPE_ZOOM__
    2 #define __GTK_PAPER_TAPE_ZOOM__
     1#ifndef __PAPER_TAPE_ZOOM__
     2#define __PAPER_TAPE_ZOOM__
     3
     4/* $Id$ */
     5
     6/* visualisation/papertape/zoom.h
     7 *
     8 * Copyright (C) 2008 Sven Koeppel
     9 *
     10 * This library is free software; you can redistribute it and/or
     11 * modify it under the terms of the GNU Library General Public
     12 * License as published by the Free Software Foundation; either
     13 * version 2 of the License, or (at your option) any later version.
     14 *
     15 * This library is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 * Library General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU Library General Public
     21 * License along with this library; if not, write to the Free
     22 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     23 */
    324
    425#include <gtkmm/dialog.h>
     
    627#include <gtkmm/action.h>
    728#include <gtkmm/spinbutton.h>
    8 
    929#include <map>
    1030
     31// uses a bit of old style GTK+
    1132#include <gtk/gtk.h>
    1233
     34namespace PaperTape
     35{ class Zoom; }
     36#include "view.h"
    1337
    14 namespace Gtk
    15 { class PaperTapeZoom; }
    16 #include "gtkpapertapeview.h"
     38namespace PaperTape {
    1739
    18 namespace Gtk {
    19 
    20 
    21 
    22 /*enum PaperTapeRotation {
     40enum Rotate {
    2341        ROTATE_90_CW,
    2442        ROTATE_90_CCW,
    2543        NO_ROTATION
    26 }*/
     44}
    2745
    28 enum PaperTapeFlip {
     46enum Flip {
    2947        FLIP_HOR,
    3048        FLIP_VER,
     
    3250};
    3351
    34 enum PaperTapeAutoZoomType {
     52enum AutoZoomType {
    3553        ZOOM_LOCHSTREIFEN_WIDTH,
    3654        ZOOM_LOCHSTREIFEN_LENGTH
    3755};
    3856
    39 class PaperTapeZoom : public Cairo::Matrix {
     57/**
     58 * The Zoom class is an extension to the Cairo Translation Matrix.
     59 * It features a nice Dialog for direct matrix editing, sigc++ signals,
     60 * automatic matrix generation from presets (Flipping, Rotation, Offsets)
     61 * and a nice clean object oriented interface.
     62 *
     63 * There's no real relation to PaperTape::View or any other class, so
     64 * you could use this class simply on your own.
     65 **/
     66
     67class Zoom : public Cairo::Matrix {
    4068        /**
    4169         * The default matrix. This is the return point whenever
     
    5280         **/
    5381        double rotation;
    54         PaperTapeFlip flip;
     82        Flip flip;
    5583        double zoom_factor;
    5684
     
    79107        sigc::signal<void> zoom_changed;
    80108public:
    81         PaperTapeZoom(double default_rotation = 0.0, double default_zoom_factor = 1.0, PaperTapeFlip default_flip = NO_FLIP);
     109        PaperTapeZoom(double default_rotation = 0.0, double default_zoom_factor = 1.0, Flip default_flip = NO_FLIP);
    82110
    83         void set_default(double rotation = 0.0, double zoom_factor = 1.0, PaperTapeFlip flip = NO_FLIP);
     111        void set_default(double rotation = 0.0, double zoom_factor = 1.0, Flip flip = NO_FLIP);
    84112
    85113        /**
     
    116144}; // class
    117145
    118 }; // namespace Gtk
     146}; // namespace PaperTape
    119147
    120 #endif // __GTK_PAPER_TAPE_ZOOM__
     148#endif // __PAPER_TAPE_ZOOM__
Note: See TracChangeset for help on using the changeset viewer.
© 2008 - 2013 technikum29 • Sven Köppel • Some rights reserved
Powered by Trac
Expect where otherwise noted, content on this site is licensed under a Creative Commons 3.0 License