`) this.enlarged.hide() this.enlarged.appendTo("body") this.enlarged.fadeIn(this.config.fadeSpeed) this.enlarged.on("click", () => this.hide()) } hide() { if (!this.enlarged) { return null; } this.enlarged.fadeOut(this.config.fadeSpeed, () => { this.enlarged.remove() this.enlarged = null }) } } function setupEnlargeableImages(target) { target.find(".enlargeable").each(function () { new EnlargeableImage($(this)) }) } setups.push(setupEnlargeableImages) // HEADLINE function setupHeadline(target) { let headline = target.find(".headline") let hasRemoveHeadline = target.find("noheadline").length > 0 let hasHeadline = headline.length > 0 let hasEmptyHeadline = headline.length > 0 && headline.html().trim() === "" if (!hasHeadline) { return } if (hasRemoveHeadline || hasEmptyHeadline) { headline.remove() } } setups.push(setupHeadline) // SLIDER class Slider { defaults = { controls: true, start: 1, // starting position speed: 200, // slide speed auto: 1, // auto-sliding autospeed: 5000, // auto-sliding interval autodirection: "right", // direction of auto-sliding ("left" or "right") dots: true, // show dots for navigation } /** * Content slider * @param element * @param config */ constructor(element, config = {}) { this.element = $(element) this._autoSlidingInterval = null // combine configurations with priority defaults -> constructor config -> data attributes this.config = $.extend({}, this.defaults, config, this.element.data()) this._validateConfig() // add refresh event this.element.on("refresh", () => this.refresh()) // wait for all images to load, so dimensions can be calculated correctly this._allImagesLoaded().then(() => { this.pos = this.config.start - 1 // starting position of the slider this.refresh() // Store original count before cloning this.originalLength = this.items.length; // skip sliding functionality if only one slide is available if(this.items.length > 1) { // auto sliding if (this.config.auto) this.startAutoSliding() // create control arrows if (this.config.controls) this.addControls() // create dots for navigation if(this.config.dots) this.addDots() } }) } _validateConfig() { let validator = new Validator(this.config, { scope: "Slider", transform: true, defaults: this.defaults, }) return validator.validate([ ["controls", "boolean"], ["start", "number"], ["start", (val) => { let slideCount = this.element.children("ul").children("li").length return val 0 }, {errorMsg: "'start' must be greater than zero and cannot exceed the number of slides"}], ["speed", "number"], ["auto", "boolean"], ["autospeed", "number"], ["autospeed", (val) => this.config.speed ["left", "right"].indexOf(val) !== -1, {errorMsg: "autodirection must be 'left' or 'right'"}] ]) } /** * refresh properties and calculated dimensions */ refresh() { this.ul = this.element.children("ul") // list containing the slides this.items = this.ul.children("li") // sliding items // reset previously set properties this.element.css({width: "", height: ""}) this.ul.css({width: "", left: ""}) this.items.css({width: "", height: ""}) // find the highest slider item and use it as the sliders height let maxSlideHeight = 0 this.items.each(function () { let slideHeight = $(this).height() if (slideHeight > maxSlideHeight) maxSlideHeight = slideHeight }) this._height = maxSlideHeight this._width = this.element.width() // slider width this._uiWidth = this.items.length * this._width // width of all items combined // set slider dimensions this.element.css({ width: this._width, height: this._height, }) this.ul.css({ width: this._uiWidth, left: this.pos * -this._width, // move viewpoint to current position }) this.items.css({ width: this._width, height: this._height, }) } /** * Add dots for navigation */ addDots() { this.dotsContainer = $('
'); // Only create dots for original slides, not cloned ones for (let i = 0; i
'); if (i === this.pos) dot.addClass('active'); dot.on('click', () => { this.stopAutoSliding(); this.moveTo(i); setTimeout(() => { if (this.config.auto) this.startAutoSliding(); }, this.config.speed + 100); }); this.dotsContainer.append(dot); } this.element.append(this.dotsContainer); } /** * update dots for navigation */ updateDots() { if (!this.config.dots) return this.dotsContainer.find('.dot').removeClass('active') this.dotsContainer.find('.dot').eq(this.pos).addClass('active') } /** * move to previous slide item or last, if there is no previous item */ prev() { // currently at the first item, prepend the last item and move there this.pos = (this.pos === 0) ? this.items.length - 1 : this.pos - 1; this.moveTo(this.pos) this.dotpos--; } /** * move to next slide item or first, if there is no next item */ next() { // currently at the last item, append the first item and move there this.pos= (this.pos === this.items.length - 1) ? 0 : this.pos+1; this.moveTo(this.pos) this.dotpos++; } /** * move to given slide item * @param pos */ moveTo(pos) { this.pos = pos this.ul.animate({left: this.pos * -this._width}, this.config.speed) this.updateDots() // update dots for navigation } /** * start auto sliding * @returns {null} */ startAutoSliding() { // abort if auto sliding is already running if (this._autoSlidingInterval !== null) return null // begin auto sliding this._autoSlidingInterval = setInterval(() => { if (this.config.autodirection === "right") this.next() else this.prev() this.updateDots() }, this.config.autospeed) } /** * stop auto sliding * @returns {null} */ stopAutoSliding() { // abort if auto sliding isn't running if (!this._autoSlidingInterval) return null // abort auto sliding clearInterval(this._autoSlidingInterval) this._autoSlidingInterval = null // Important: Reset the interval } /** * toggle auto sliding * @returns {null} */ toggleAutoSliding() { if (this._autoSlidingInterval) this.startAutoSliding() else this.stopAutoSliding() } /** * Add control arrows to slide to the next or previous item */ addControls() { if (!this.controlPrev) { this.controlPrev = $('
') this.controlPrev.on("click", () => { this.stopAutoSliding() this.prev() }); this.element.prepend(this.controlPrev) } if (!this.controlNext) { this.controlNext = $('
') this.controlNext.on("click", () => { this.stopAutoSliding() this.next() }); this.element.prepend(this.controlNext) } } /** * remove control arrows */ removeControls() { if (this.controlPrev) this.controlPrev.remove() if (this.controlNext) this.controlNext.remove() } /** * promise to wait for loading of all images within the slider * @returns {Promise} */ async _allImagesLoaded() { let loadPromises = [] this.element.find("img").each((i, imageElement) => { loadPromises.push(new Promise(res => { $("").on("load", () => res()).attr("src", $(imageElement).attr("src")) })) }) await Promise.all(loadPromises) } } function setupSliders(target) { target.find(".slider").each(function () { new Slider($(this)) }) } setups.push(setupSliders) // TABLE OF CONTENTS class TableOfContents { defaults = { auto: true, // try to automatically generate the toc scrollspeed: 500, // animation duration of scroll effect when a link is clicked scrolloffset: 200, // offset for headingsselector: "[data-accordion]:not(.no-toc),.toc", // selector for relevant content headings, that should be included in the toc } /** * Content slider * @param element {jQuery|HTMLElement} * @param config {object} */ constructor(element, config = {}) { this.element = $(element) // combine configurations with priority defaults -> constructor config -> data attributes this.config = $.extend({}, this.defaults, config, this.element.data()) this._validateConfig() // automatically create toc if (this.config.auto) this.update() } _validateConfig() { let validator = new Validator(this.config, { scope: "TableOfContents", transform: true, defaults: this.defaults, }) return validator.validate([ ["auto", "boolean"], ["scrollspeed", "number"], ["scrolloffset", "number"], ["scrollselector", "string"], ["headingsselector", "string"], ]) } /** * re-render the table of contents box */ update() { const data = this._retrieveTocData() const tocBox = $(`

Inhaltsverzeichnis

`) const tocList = this._createIndexList(data) this.element.html("") tocBox.append(tocList) this.element.append(tocBox) } /** * searches the document for headings and sorts them hierarchically * Output: * [ * { * level: (int), // heading level from 1 to 6 * title: (string), // heading title * id: (string), // element DOM id (optional) * children: [ // headings that are of a lower level and followed this heading * {level: ..., title, ...}, * ] * }, ... * ] * @returns {*[]} * @private */ _retrieveTocData() { const headings = $(this.config.headingsselector) const tocData = []; const stack = []; $.each(headings, (i, heading) => { heading = $(heading) const level = this._getHeadingLevel(heading) const title = this._getHeadingTitle(heading) const id = this._getHeadingId(heading) if (!level || !title) return null const node = {level: level, title: title, id: id, element: heading}; while (stack.length > 0 && stack[stack.length - 1].level >= level) { stack.pop(); } if (stack.length > 0) { const parent = stack[stack.length - 1]; if (!parent.children) { parent.children = []; } parent.children.push(node); } else { tocData.push(node); } stack.push(node); }) return tocData; } /** * Tries to retrieve the heading level (1-6) from an element by the following methods in this order: * 1. By data-attribute (e.g. data-level="1") * 2. By class (e.g. class="h1") * 3. By Tag (e.g.

) * @param heading {jQuery|HTMLElement} * @returns {null|number} * @private */ _getHeadingLevel(heading) { const hRegex = "\\b[hH][1-6]\\b" const byData = heading.data("level") if (byData) return parseInt(byData) const byClass = heading.attr("class") ? heading.attr("class").match(hRegex) : null if (byClass) return parseInt(byClass[0].slice(1)) const byTag = heading.prop("tagName").match(hRegex) if (byTag) return parseInt(byTag[0].slice(1)) return null } /** * Tries to retrieve the heading title from an element by the following methods in this order: * 1. By data (e.g. data-title="Hello World") * 2. By content, stripping all html tags in the process (e.g.

Hello World

) * @param heading {jQuery|HTMLElement} * @returns {null|string} * @private */ _getHeadingTitle(heading) { const byData = heading.data("title") if (byData) return byData const byContent = heading.html() ? heading.text().trim() : null if (byContent) return byContent return null } /** * Tries to retrieve the heading ID from an element by the following methods in this order: * 1. By ID (e.g. id="my-element") * 2. By Accordion-Target (e.g. data-accordion="#my-element") * @param heading {jQuery|HTMLElement} * @returns {*|jQuery|string|null} * @private */ _getHeadingId(heading) { const byId = heading.attr("id") if (byId) return byId let byAccordion = heading.data("accordion") byAccordion = byAccordion && byAccordion[0] === "#" ? byAccordion.substring(1) : null if (byAccordion) return byAccordion return null } /** * Creates an element with a numbered list based on the given data (see: this._retrieveTocData()) * Lower levels are indented and get their own running number, separated by a point (e.g. 2.1.-2.4 as children of 2.) * @param tocNodesData {[]} * @returns {jQuery|HTMLElement} * @private */ _createIndexList(tocNodesData) { let list = $('
    ') $.each(tocNodesData, (i, node) => { // create list item with heading title let listItem = $(`
  1. `) let itemLink = $(`${node.title}`) // scroll to the connected heading element on click itemLink.on("click", (e) => { scrollTo(node.element, this.config.scrollspeed, this.config.scrolloffset) }) listItem.append(itemLink) // add list item list.append(listItem) // append list of children to the next level of the list if(typeof node.children !== "undefined") { listItem.append(this._createIndexList(node.children)) } }) return list } } function setupTableOfContents(target) { target.find(".table-of-contents").each(function () { new TableOfContents($(this)) }) } setups.push(setupTableOfContents) // Validator class Validator { defaults = { transform: false, // try to transform values into the desired format consoleErrors: true, // print errors to console scope: false, // print scope to error messages to identify the validation messages defaults: {} // default values to reset the variable to if the validation failed } /** * @param data {{}} * @param config {{}} */ constructor(data, config = []) { this.data = data this.config = $.extend({}, this.defaults, config) } /** * Validate a given array of validator configurations * @param validators {[]} * @returns {*[]} */ validate(validators = []) { if (!Array.isArray(validators)) return null let failed = [] validators.forEach(validatorConfig => { let varName = validatorConfig[0] let validatorFunc = validatorConfig[1] let userConfig = validatorConfig[2] || {} let isValid = false if (typeof validatorFunc === "string" && typeof this[validatorFunc] === "function") { // validatorFunc is a standard method of Validator isValid = this[validatorFunc](varName, userConfig) } else if (typeof validatorFunc === "function") { // validatorFunc is a custom validation isValid = this._execValidator({ varName: varName, validator: validatorFunc, }, userConfig) } // validation failed, list the variable name as failed if (!isValid) failed.push(validatorConfig.varName) }) // return the names of all failed validations return failed } /** * Execute standard or custom validator configuration * @param config {{}} * @param customConfig {{}} * @returns boolean * @private */ _execValidator(config, customConfig) { // merge the configuration with priority default -> config given to constructor -> standard method config -> custom validator config config = $.extend({}, this.config, config, customConfig) config = this._validateConfiguration(config) if (!config) return false let val = config.val // transform the variable if configured to do so and set it to the given dataset if the validation is successful val = config.transform ? config.transformator(val) : val let isValid = config.validator(val, this) if (isValid && config.transform) this.data[config.varName] = val // print errors if configured to do so if (config.consoleErrors && !isValid) console.error(`${config.scope ? `${config.scope}: ` : ''}${config.errorMsg}`) // set default value if it exists and the validation failed if (!isValid && this.config.defaults.hasOwnProperty(config.varName)) this.data[config.varName] = this.config.defaults[config.varName] return isValid } /** * Validate the validator configuration itself * @param config {{}} * @returns {boolean|*} * @private */ _validateConfiguration(config) { // is the validator executable? if (typeof config.validator !== "function") { console.error("validator is not a function") return false } // does the validator know what it should validate? if (!config.varName) { console.error("varName must be set in validation configuration") return false } // set default configurations if no custom configuration was set config.errorMsg = config.errorMsg || `Validation failed for ${config.varName}` config.transform = config.transform || this.config.transform config.transformator = config.transformator || function (val) { return val } // read variables value from dataset config.val = this.data[config.varName] return config } /** * Validate if variable contains a boolean (or something that could be interpreted as one) * @param varName {string} * @param config {{}} * @returns {boolean} */ boolean(varName, config) { return this._execValidator({ varName: varName, transformator: (val) => { if (["0", 0, "false", "False", "FALSE", "F", "f"].indexOf(val) !== -1) return false if (["1", 1, "true", "True", "TRUE", "T", "t"].indexOf(val) !== -1) return true return val }, validator: (val) => typeof val == "boolean", errorMsg: `${varName} must be boolean` }, config) } /** * Validate if variable contains a numeric value * @param varName {string} * @param config {{}} * @returns {boolean} */ number(varName, config) { return this._execValidator({ varName: varName, transformator: (val) => Number(val), validator: (val) => !isNaN(val), errorMsg: `${varName} must be a number` }, config) } /** * Validate if variable contains a string value * @param varName {string} * @param config {{}} * @returns {boolean} */ string(varName, config) { return this._execValidator({ varName: varName, transformator: (val) => String(val), validator: (val) => typeof val === "string" || val instanceof String, errorMsg: `${varName} must be a string` }, config) } } // SETUPS $(document).ready(function () { let main = $("#main"); $.each(setups, (i, setupFunction) => { if (typeof setupFunction === "function") { setupFunction(main) } }) // fix scrolling to anchor const anchor = window.location.hash; if(anchor !== "") scrollTo(`${anchor}, [data-accordion="${anchor}"]`); }) // Scroll method function scrollTo(target, speed, offset) { target = $(target) speed = speed ?? 0 offset = offset ?? 200 const scrollContainer = $("#scrollable-area") target.trigger("Accordion:show") let position = target.offset().top - scrollContainer.offset().top + scrollContainer.scrollTop() - offset; scrollContainer.animate({ scrollTop: position }, speed); } // Fix navigation height when the page is scrolled and the menu is moved to the top function fixedNav() { let viewportWidth = $(window).width(); let main = $('#main'); let scrollableArea = $("#scrollable-area"); let headerLogoContainer = $("#header-logo-container"); let navigationContainerMobile = $('#navigation-container-mobil'); let navigationContainer = $('#navigation-container'); if (viewportWidth headerLogoContainer.height() + 3) { navigationContainerMobile.css('width', navigationContainerMobile.width() + "px"); main.css('padding-top', navigationContainerMobile.height() + 'px'); // ADD TO ORIGINAL SCRIPT: main.css('background-position', '0 ' + (parseInt(navigationContainerMobile.height()) * 2) + 'px'); navigationContainerMobile.css('position', 'fixed'); navigationContainerMobile.css('top', '0'); } else { navigationContainerMobile.css('width', "100%"); main.css('padding-top', '0'); // ADD TO ORIGINAL SCRIPT: main.css('background-position', '0 ' + navigationContainerMobile.height() + 'px'); navigationContainerMobile.css('position', 'relative'); } } else { if (scrollableArea.scrollTop() > headerLogoContainer.height() + 3) { navigationContainer.css('width', navigationContainer.width() + "px"); main.css('padding-top', navigationContainer.height() + 'px'); // ADD TO ORIGINAL SCRIPT: main.css('background-position', '0 ' + (parseInt(navigationContainerMobile.height()) * 2) + 'px'); navigationContainer.css('position', 'fixed'); navigationContainer.css('top', '0'); } else { navigationContainer.css('width', "100%"); main.css('padding-top', '0'); // ADD TO ORIGINAL SCRIPT: main.css('background-position', '0 ' + navigationContainerMobile.height() + 'px'); navigationContainer.css('position', 'relative'); } } }

    Mitgliederliste

    Fakultät für Biologie und Psychologie

    Prof. Dr. Hannes Rakoczy

    Hochschullehrer*innen
    Entwicklungspsychologie
    E-Mail
    Website

    Prof. Dr. Sascha Schroeder

    Hochschullehrer*innen
    Pädagogische Psychologie
    E-Mail
    Website

    Prof. Dr. Susanne Bögeholz

    Hochschullehrer*innen
    Didaktik der Biologie
    E-Mail
    Website

    Jacqueline Dischereit

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Astrid Haase

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Alexander Stern

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Tanya Behne

    Mitarbeiter*innen
    E-Mail
    Website

    Anna Lena Fischer

    Studierende

    Fakultät für Chemie

    Prof. Dr. Thomas Waitz

    Hochschullehrer*innen
    Fachdidaktik Chemie
    E-Mail
    Website

    Dr. Regine Herbst-Irmer

    Mitarbeiter*innen
    E-Mail
    Website

    Pauline Hartmann

    Studierende

    Fakultät für Geowissenschaften und Geographie

    N.N. (Erdkunde)

    Hochschullehrer*innen
    Erdkunde

    Dr. Tobias Reeh

    Mitarbeiter*innen
    E-Mail
    Website

    Jaron Akkermann

    Studierende

    Fakultät für Mathematik und Informatik

    Prof. Dr. Kerstin Strecker

    Hochschullehrer*innen
    Didaktik der Informatik
    E-Mail
    Website

    Prof. Dr. Stefan Halverscheid

    Hochschullehrer*innen
    Didaktik der Mathematik
    E-Mail
    Website

    Simon Steuernagel

    Mitarbeiter*innen
    E-Mail
    Website

    Tom Kohl

    Studierende

    Fakultät für Physik

    Prof. Dr. Pascal Klein

    Hochschullehrer*innen
    Physik und ihre Didaktik
    E-Mail
    Website

    Prof. Dr. Susanne Schneider

    Hochschullehrer*innen
    Didaktik der Physik
    E-Mail
    Website

    Jasper Ole Cirkel

    Mitarbeiter*innen
    E-Mail
    Website

    Alisa Orth

    Studierende

    Philosophische Fakultät

    Prof. Dr. Anne Burkard

    Hochschullehrer*innen
    Didaktik der Philosophie und das Fach Werte und Normen
    E-Mail
    Website

    Prof. Dr. Birgit Schädlich

    Hochschullehrer*innen
    Didaktik der Romanischen Sprachen und Literaturen
    E-Mail
    Website

    Dr. Tanyasha Yearwood

    Hochschullehrer*innen
    Englische Fachdidaktik
    E-Mail
    Website

    Prof. Dr. Christoph Bräuer

    Hochschullehrer*innen
    Didaktik der Deutschen Sprache und Literatur
    E-Mail
    Website

    Prof. Dr. Tao Zhang

    Hochschullehrer*innen
    Fachdidaktik Chinesisch
    E-Mail
    Website

    Prof. Dr. Marta García García

    Hochschullehrer*innen
    Didaktik der Romanischen Sprachen und Literaturen
    E-Mail
    Website

    Prof. Dr. Kathrin Klausmeier

    Hochschullehrer*innen
    Didaktik der Geschichte
    E-Mail
    Website

    Prof. Dr. Peter Alois Kuhlmann

    Hochschullehrer*innen
    Lateinische Philologie und Fachdidaktik der Alten Sprachen
    E-Mail
    Website

    Prof. Dr. Torsten Pflugmacher

    Hochschullehrer*innen
    Didaktik der Deutschen Sprache und Literatur
    E-Mail
    Website

    N.N. (Russisch)

    Hochschullehrer*innen
    Russisch

    Johannes Wegener

    Mitarbeiter*innen
    E-Mail
    Website

    Gitta Windt

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Silke Kubik

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Nils Jäger

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Ksenia Kuzminykh

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Andreas Wirag

    Mitarbeiter*innen
    E-Mail
    Website

    Moritz Wille

    Studierende

    Yara Zoch

    Studierende

    Sozialwissenschaftliche Fakultät

    Prof. Dr. Ariane Willems

    Hochschullehrer*innen
    Empirische Bildungsforschung
    E-Mail
    Website

    Prof. Dr. Hermann Veith

    Hochschullehrer*innen
    Pädagogik mit dem Schwerpunkt Sozialisationsforschung
    E-Mail
    Website

    Dr. Yoon-Sun Huh

    Hochschullehrer*innen
    Sport und Pädagogik (Didaktik)
    E-Mail
    Website

    Jun.-Prof. Dr. Jessica Löser

    Hochschullehrer*innen
    Inklusiver gymnasialer Fachunterricht
    E-Mail
    Website

    Prof. Dr. Katharina Kunze

    Hochschullehrer*innen
    Erziehungswissenschaft mit dem Schwerpunkt Pädagogisches Handeln und Professionalität
    E-Mail
    Website

    Prof. Dr. Kerstin Rabenstein

    Hochschullehrer*innen
    Schulpädagogik / Empirische Unterrichtsforschung und Schulentwicklung
    E-Mail
    Website

    Prof. Dr. Klaus-Peter Horn

    Hochschullehrer*innen
    Allgemeine und Historische Erziehungswissenschaft
    E-Mail
    Website

    Dr. Christine Engartner

    Hochschullehrer*innen
    Politikwissenschaft / Didaktik der Politik
    E-Mail
    Website

    Prof. Dr. Tobias C. Stubbe

    Hochschullehrer*innen
    E-Mail
    Website

    Dr. Susanne Masuch

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Christina Radicke

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Dorthe Petersen

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Marcel Grieger

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Johanna Leunig

    Mitarbeiter*innen
    E-Mail
    Website

    Paulina Dužević

    Studierende

    Theologische Fakultät

    Prof. Dr. Bernd Schröder

    Hochschullehrer*innen
    Praktische Theologie mit den Schwerpunkten Religionspädagogik und Bildungsforschung
    E-Mail
    Website

    Dr. Moritz Emmelmann

    Mitarbeiter*innen
    E-Mail
    Website

    Johanna Keßler

    Studierende

    ZEWIL

    Dr. Soheyla Pashang

    MTV
    E-Mail
    Website

    Dr. Jörg Behrendt

    MTV
    E-Mail
    Website

    Joana Schröer-Reuter

    MTV
    E-Mail
    Website

    Dr. Melanie Lukas

    MTV
    E-Mail
    Website

    Robert Müller

    MTV
    E-Mail
    Website

    Berlind Falck

    Mitarbeiter*innen
    E-Mail
    Website

    Dr. Sabina Eggert

    Mitarbeiter*innen
    E-Mail
    Website

    Mitgliedschaft

    Sie haben Interesse an einer Mitgliedschaft oder möchten eine Person als Mitglied vorschlagen? Wenden Sie sich hierzu an den Referenten der ZEWIL.

    Kontakt

    Melanie Lukas 554

    Dr. Melanie Lukas

    Fachreferent*in im Projektmanagement der ZEWIL, stellv. Gleichstellungsbeauftragte

    melanie.lukas@uni-goettingen.de

    Sprechzeiten: nach Vereinbarung
    logo_1200_transparent