Basisinformationstechnologie I 
Universität zu Köln. Historisch-Kulturwissenschaftliche Informationsverarbeitung 
Jan G. Wieners // jan.wieners@uni-koeln.de 
Wintersemester 2014/15 
17. Dezember 2014 – Programmiersprachen I
Themenüberblick „Programmiersprachen I“ 
Phasen der Programmentwicklung 
 Analyse 
 Spezifikation 
 Entwurf 
 Algorithmus 
 Pseudocode 
 Implementation 
 Post-Implementation 
Programmiersprachen 
 Compiler / Interpreter 
 Typisierung 
 Paradigmen 
 Objektorientierung
Neulich in den 
Sommerferien…
Analyse
Programmentwicklung: Analyse 
Descartes (1596-1650) 
„Regeln zur Leitung des 
Geistes" (1628): 
 Hohe Relevanz der 
Analysephase 
 Aufteilung in Teil- und 
Unterprobleme 
 Hierarchischer 
Erkenntnisprozess 
 Analyse der Analyse 
i.e. Sicherung der Analyse
Programmentwicklung: Algorithmus 
Spezifikation: Problembeschreibung – im Gegensatz 
zum Algorithmus, der die Lösung des Problems angibt 
Algorithmus: Anleitung oder Vorschrift, wie sich ein 
Problem lösen lässt 
 Arbeitsdefinition Algorithmus: Eindeutige 
Beschreibung eines endlichen Verfahrens zur Lösung 
einer bestimmten Klasse von Problemen 
Algorithmus im Labyrinthbeispiel: Verfahren, um aus 
dem dunklen Labyrinth zu gelangen
Entwurf
Finden Sie einen Weg aus dem Labyrinth
Entwerfen Sie einen Algorithmus, der Sie aus jedem Labyrinth (mit Ausgang) führt
Terminierung von Algorithmen: 
Wir verlangen (zumeist) von 
Algorithmen, dass sie terminieren, 
d.h. dass sie in endlicher Zeit (und 
möglichst schnell  Performance) 
ihre Arbeit erledigt haben 
Entwerfen Sie einen Algorithmus, der Sie aus jedem Labyrinth (mit Ausgang) führt
Programmentwicklung: Entwurfsphase III 
Pledge-Algorithmus: 
 Prämisse: Wir gehen davon aus, dass alle Ecken rechtwinklig 
sind 
 Somit kommen nur Rechtsdrehungen und Linksdrehungen um 
jeweils 90 Grad vor 
 Wir verwalten unterwegs einen Umdrehungszähler, der: 
 bei jeder Linksdrehung um eins erhöht und 
 bei jeder Rechtsdrehung um eins verringert wird (auch bei der 
ersten Rechtsdrehung, die nach dem Auftreffen auf eine Wand 
ausgeführt wird). 
 Zu Beginn wird dieser Umdrehungszähler auf null gesetzt 
 Anschließend werden die beiden Anweisungen 
 geradeaus, bis Wand erreicht 
 Folge der Wand, bis Umdrehungszähler = 0 
solange wiederholt, bis wir ins Freie gelangen
Pseudocode 
Pseudocode Pledge-Algorithmus: 
 Setze Umdrehungszähler auf 0; 
 Wiederhole 
 Wiederhole 
 Gehe geradeaus; 
 Solange Wand erreicht; 
 Drehe nach rechts; 
 Wiederhole 
 Folge dem Hindernis; 
 Solange Umdrehungszähler=0; 
 Solange ins Helle gelangt; 
 Der Entwurf ist unabhängig von der Programmiersprache!
Implementation 
Programmerstellung und Programmiersprachen
Programmiersprachen
Strukturierte Computerorganisation 
Problemorientierte Sprache 
Assemblersprache 
Betriebssystemmaschine 
Befehlssatzarchitektur (ISA) 
Mikroarchitektur 
Digitale Logik 
Ebene 5 
Ebene 4 
Ebene 3 
Ebene 2 
Ebene 1 
Ebene 0
Programmiersprachen: Klassifizierung 
Maschinennahe Programmiersprache: Assembler 
Beispiel: „Hello World“ : 
DATA SEGMENT ;- Beginn des Datensegments 
Meldung db "Hello World" ;- Die Zeichenkette "Hello World" 
db "$" ;- Endzeichen der Zeichenkette 
DATA ENDS ;- Ende des Datensegment 
CODE SEGMENT ;- Beginn des Codesegements 
ASSUME CS:CODE,DS:DATA ;- Dem Assembler die Segmente mitteilen 
Anfang: ;- Label für den Anfang des Programms 
mov ax, DATA ;- das Daten... 
mov ds, ax ; ...segment festlegen 
mov dx, offset Meldung ;- den Text in das auf DS bezogene Datenregister 
laden 
mov ah, 09h ;- Die Unterfunktion 9 des Betriebssysteminterrupts 
21h auswählen 
int 21h ;- den Betriebssysteminterrupt 21h (hier erfolgt 
Ausgabe des Texts) aufrufen 
mov ax, 4C00h ;- Die Unterfunktion 4Ch (Programmbeendigung) des 
Betriebssysteminterrupts 21h festlegen 
int 21h ;- diesen Befehl wiederum ausführen 
CODE ENDS ;- Ende des Codesegments 
END Anfang ;- dem Assembler das Ende des Labels Anfang mitteilen 
Vgl.: http://de.wikipedia.org/wiki/Assemblersprache
Programmiersprachen 
Anweisungen, die wir dem Computer geben, werden als Text 
formuliert, z.B.: 
In Python: 
print "Hello World!" 
In PHP: 
print "Hello World!"; 
In JavaScript: 
document.write("Hello World!"); 
In C++: 
cout << "Hello World";
Programmiersprachen 
Programmtext ist formuliert nach festen Regeln: 
Beispiel C++: 
cout << "Hello World"; 
Die Regeln (Grammatik) der Programmiersprache 
C++ schreiben vor, dass der Ausdruck 
cout << "Hello World" 
mit einem Semikolon abgeschlossen werden 
muss
Spracheigenschaften und 
Programmierparadigmen
? var beispiel = 23;
Deklaration und Initialisierung 
In JavaScript: 
// Deklaration 
var eineVariable, eineWeitereVariable; 
// Initialisierung 
eineVariable = 23; 
eineWeitereVariable = “Hello World!“;
Typisierung 
Variablen: Behälter / Speicherstelle; Typisierung  Typ 
der Variable 
In JavaScript: 
// Deklaration 
var eineVariable, eineWeitereVariable; 
 Dynamische Typisierung 
In C++: 
int eineVariable = 23; 
char eineWeitereVariable[]="Hello World"; 
 Statische Typisierung 
Datentyp
Datentypen (C++) 
Einfache Datentypen in C++: 
 bool  Wahrheitswerte 
 int  ganze Zahlen 
 unsigned int  Natürliche Zahlen 
 float  Fließkommazahlen 
 double  Fließkommazahlen, doppelte Genauigkeit 
 char  Zeichen 
Zusammengesetzte Datentypen (in C++): 
 string  Zeichenketten 
 array  Sammlung von Daten eines Datentyps
Doppelte Genauigkeit…?!?
Paradigmen: 
 funktional 
 objektorientiert 
 prozedural 
 etc. etc. etc.
Programmierparadigmen: Funktionale Programmierung 
var randomize = function( lowerBound, 
upperBound ) { 
if( lowerBound > upperBound ) { 
return( -1 ); 
} 
if( lowerBound === upperBound ) { 
return( lowerBound ); 
} 
return lowerBound + parseInt( 
Math.random() * ( upperBound-lowerBound+1 ), 
10); 
}
Objektorientierte Programmierung 
Objektorientierte Programmierung [C++, Java] 
 Zentrales Konzept: Objekt 
 Objekt 
 Verfügt über einen bestimmten Zustand 
 Reagiert mit einem definierten Verhalten auf 
Anforderungen / seine Umgebung 
 Besitzt eine Identität, die es von anderen Objekten 
unterscheidet 
 Kann mit anderen Objekten verbunden sein
Objektorientierung
Kapselung, Information Hiding, Geheimnisprinzip 
Abb.: Balzert, Heide: Lehrbuch der Objektmodellierung. Heidelberg, 2005.
Zentrales Konzept I: Klassen 
Gleichartige Objekte (Objekte mit denselben 
Operationen und gleichen Attributen) gehören zur 
gleichen Klasse. 
Abstrakt vs. konkret: Jedes Objekt ist Exemplar bzw. 
Instanz einer Klasse 
Klasse: Definiert für eine Sammlung von Objekten 
deren 
 Struktur (Attribute) 
 Verhalten (Operationen) 
 Beziehungen 
 Verfügt über Mechanismen, um neue Objekte zu erzeugen 
(Object Factory)
Klassen in C++  Kapselung / Information Hiding 
class EineKlasse 
{ 
public: // öffentlicher Teil 
EineKlasse() // Konstruktor 
{ 
klassenVariable=23; 
} 
~EineKlasse(); // Destruktor 
int gebeVariablezurueck(void) 
{ 
return klassenVariable; 
} 
private: // privater Teil 
int klassenVariable; // private Variable 
};
Notation von Klassen 
Abb.: Balzert, Heide: Lehrbuch der Objektmodellierung. Heidelberg, 2005.
Zentrales Konzept II: Vererbung 
 Eine Klasse kann Elemente (Variablen, Konstanten, Funktionen) von 
anderen Klassen erben 
Beispiel C++: 
class Person 
{ 
string name; 
//... 
}; 
class Mitarbeiter : Person 
{ 
long sozialversicherungsNr; 
//... 
};
Martial Arts Objects (Vererbung) 
Martial Arts Fighter 
attribute 1: name 
attribute 2: gender 
attribute 2: two legs 
attribute 3: two arms 
behaviour 1: getName() 
behaviour 2: walk() 
behaviour 3: bong_sau() 
behaviour 4: tan_sau()
Objektorientierte Programmiersprache: C++ 
C++: 
 Ermöglicht maschinennahe Programmierung (Stichw. 
„Zeiger“), als auch abstrakte Programmierung (i.e. 
Objektorientierung) 
 Kompilierung über g++ Compiler, Microsoft Visual C++ 
Compiler, etc.
Objektorientierte Programmiersprachen: Java 
Java 
 Besonderheit: Java-Programme werden in Bytecode übersetzt, 
anschließend in einer Java-Laufzeitumgebung ausgeführt  
Virtuelle Maschine (VM) 
 Vorteil: Plattformunabhängigkeit: Java-Programme laufen 
(zumeist) ohne weitere Anpassungen auf unterschiedlichen 
Computer- und Betriebssystemen, für die eine Java-VM 
existiert
/

BIT I WiSe 2014 | Basisinformationstechnologie I - 08: Programmiersprachen I

  • 1.
    Basisinformationstechnologie I Universitätzu Köln. Historisch-Kulturwissenschaftliche Informationsverarbeitung Jan G. Wieners // jan.wieners@uni-koeln.de Wintersemester 2014/15 17. Dezember 2014 – Programmiersprachen I
  • 2.
    Themenüberblick „Programmiersprachen I“ Phasen der Programmentwicklung  Analyse  Spezifikation  Entwurf  Algorithmus  Pseudocode  Implementation  Post-Implementation Programmiersprachen  Compiler / Interpreter  Typisierung  Paradigmen  Objektorientierung
  • 3.
    Neulich in den Sommerferien…
  • 10.
  • 11.
    Programmentwicklung: Analyse Descartes(1596-1650) „Regeln zur Leitung des Geistes" (1628):  Hohe Relevanz der Analysephase  Aufteilung in Teil- und Unterprobleme  Hierarchischer Erkenntnisprozess  Analyse der Analyse i.e. Sicherung der Analyse
  • 12.
    Programmentwicklung: Algorithmus Spezifikation:Problembeschreibung – im Gegensatz zum Algorithmus, der die Lösung des Problems angibt Algorithmus: Anleitung oder Vorschrift, wie sich ein Problem lösen lässt  Arbeitsdefinition Algorithmus: Eindeutige Beschreibung eines endlichen Verfahrens zur Lösung einer bestimmten Klasse von Problemen Algorithmus im Labyrinthbeispiel: Verfahren, um aus dem dunklen Labyrinth zu gelangen
  • 13.
  • 14.
    Finden Sie einenWeg aus dem Labyrinth
  • 15.
    Entwerfen Sie einenAlgorithmus, der Sie aus jedem Labyrinth (mit Ausgang) führt
  • 16.
    Terminierung von Algorithmen: Wir verlangen (zumeist) von Algorithmen, dass sie terminieren, d.h. dass sie in endlicher Zeit (und möglichst schnell  Performance) ihre Arbeit erledigt haben Entwerfen Sie einen Algorithmus, der Sie aus jedem Labyrinth (mit Ausgang) führt
  • 17.
    Programmentwicklung: Entwurfsphase III Pledge-Algorithmus:  Prämisse: Wir gehen davon aus, dass alle Ecken rechtwinklig sind  Somit kommen nur Rechtsdrehungen und Linksdrehungen um jeweils 90 Grad vor  Wir verwalten unterwegs einen Umdrehungszähler, der:  bei jeder Linksdrehung um eins erhöht und  bei jeder Rechtsdrehung um eins verringert wird (auch bei der ersten Rechtsdrehung, die nach dem Auftreffen auf eine Wand ausgeführt wird).  Zu Beginn wird dieser Umdrehungszähler auf null gesetzt  Anschließend werden die beiden Anweisungen  geradeaus, bis Wand erreicht  Folge der Wand, bis Umdrehungszähler = 0 solange wiederholt, bis wir ins Freie gelangen
  • 18.
    Pseudocode Pseudocode Pledge-Algorithmus:  Setze Umdrehungszähler auf 0;  Wiederhole  Wiederhole  Gehe geradeaus;  Solange Wand erreicht;  Drehe nach rechts;  Wiederhole  Folge dem Hindernis;  Solange Umdrehungszähler=0;  Solange ins Helle gelangt;  Der Entwurf ist unabhängig von der Programmiersprache!
  • 20.
  • 21.
  • 22.
    Strukturierte Computerorganisation ProblemorientierteSprache Assemblersprache Betriebssystemmaschine Befehlssatzarchitektur (ISA) Mikroarchitektur Digitale Logik Ebene 5 Ebene 4 Ebene 3 Ebene 2 Ebene 1 Ebene 0
  • 23.
    Programmiersprachen: Klassifizierung MaschinennaheProgrammiersprache: Assembler Beispiel: „Hello World“ : DATA SEGMENT ;- Beginn des Datensegments Meldung db "Hello World" ;- Die Zeichenkette "Hello World" db "$" ;- Endzeichen der Zeichenkette DATA ENDS ;- Ende des Datensegment CODE SEGMENT ;- Beginn des Codesegements ASSUME CS:CODE,DS:DATA ;- Dem Assembler die Segmente mitteilen Anfang: ;- Label für den Anfang des Programms mov ax, DATA ;- das Daten... mov ds, ax ; ...segment festlegen mov dx, offset Meldung ;- den Text in das auf DS bezogene Datenregister laden mov ah, 09h ;- Die Unterfunktion 9 des Betriebssysteminterrupts 21h auswählen int 21h ;- den Betriebssysteminterrupt 21h (hier erfolgt Ausgabe des Texts) aufrufen mov ax, 4C00h ;- Die Unterfunktion 4Ch (Programmbeendigung) des Betriebssysteminterrupts 21h festlegen int 21h ;- diesen Befehl wiederum ausführen CODE ENDS ;- Ende des Codesegments END Anfang ;- dem Assembler das Ende des Labels Anfang mitteilen Vgl.: http://de.wikipedia.org/wiki/Assemblersprache
  • 24.
    Programmiersprachen Anweisungen, diewir dem Computer geben, werden als Text formuliert, z.B.: In Python: print "Hello World!" In PHP: print "Hello World!"; In JavaScript: document.write("Hello World!"); In C++: cout << "Hello World";
  • 25.
    Programmiersprachen Programmtext istformuliert nach festen Regeln: Beispiel C++: cout << "Hello World"; Die Regeln (Grammatik) der Programmiersprache C++ schreiben vor, dass der Ausdruck cout << "Hello World" mit einem Semikolon abgeschlossen werden muss
  • 27.
  • 29.
  • 30.
    Deklaration und Initialisierung In JavaScript: // Deklaration var eineVariable, eineWeitereVariable; // Initialisierung eineVariable = 23; eineWeitereVariable = “Hello World!“;
  • 31.
    Typisierung Variablen: Behälter/ Speicherstelle; Typisierung  Typ der Variable In JavaScript: // Deklaration var eineVariable, eineWeitereVariable;  Dynamische Typisierung In C++: int eineVariable = 23; char eineWeitereVariable[]="Hello World";  Statische Typisierung Datentyp
  • 32.
    Datentypen (C++) EinfacheDatentypen in C++:  bool  Wahrheitswerte  int  ganze Zahlen  unsigned int  Natürliche Zahlen  float  Fließkommazahlen  double  Fließkommazahlen, doppelte Genauigkeit  char  Zeichen Zusammengesetzte Datentypen (in C++):  string  Zeichenketten  array  Sammlung von Daten eines Datentyps
  • 33.
  • 34.
    Paradigmen:  funktional  objektorientiert  prozedural  etc. etc. etc.
  • 35.
    Programmierparadigmen: Funktionale Programmierung var randomize = function( lowerBound, upperBound ) { if( lowerBound > upperBound ) { return( -1 ); } if( lowerBound === upperBound ) { return( lowerBound ); } return lowerBound + parseInt( Math.random() * ( upperBound-lowerBound+1 ), 10); }
  • 36.
    Objektorientierte Programmierung ObjektorientierteProgrammierung [C++, Java]  Zentrales Konzept: Objekt  Objekt  Verfügt über einen bestimmten Zustand  Reagiert mit einem definierten Verhalten auf Anforderungen / seine Umgebung  Besitzt eine Identität, die es von anderen Objekten unterscheidet  Kann mit anderen Objekten verbunden sein
  • 37.
  • 38.
    Kapselung, Information Hiding,Geheimnisprinzip Abb.: Balzert, Heide: Lehrbuch der Objektmodellierung. Heidelberg, 2005.
  • 39.
    Zentrales Konzept I:Klassen Gleichartige Objekte (Objekte mit denselben Operationen und gleichen Attributen) gehören zur gleichen Klasse. Abstrakt vs. konkret: Jedes Objekt ist Exemplar bzw. Instanz einer Klasse Klasse: Definiert für eine Sammlung von Objekten deren  Struktur (Attribute)  Verhalten (Operationen)  Beziehungen  Verfügt über Mechanismen, um neue Objekte zu erzeugen (Object Factory)
  • 40.
    Klassen in C++ Kapselung / Information Hiding class EineKlasse { public: // öffentlicher Teil EineKlasse() // Konstruktor { klassenVariable=23; } ~EineKlasse(); // Destruktor int gebeVariablezurueck(void) { return klassenVariable; } private: // privater Teil int klassenVariable; // private Variable };
  • 41.
    Notation von Klassen Abb.: Balzert, Heide: Lehrbuch der Objektmodellierung. Heidelberg, 2005.
  • 42.
    Zentrales Konzept II:Vererbung  Eine Klasse kann Elemente (Variablen, Konstanten, Funktionen) von anderen Klassen erben Beispiel C++: class Person { string name; //... }; class Mitarbeiter : Person { long sozialversicherungsNr; //... };
  • 43.
    Martial Arts Objects(Vererbung) Martial Arts Fighter attribute 1: name attribute 2: gender attribute 2: two legs attribute 3: two arms behaviour 1: getName() behaviour 2: walk() behaviour 3: bong_sau() behaviour 4: tan_sau()
  • 44.
    Objektorientierte Programmiersprache: C++ C++:  Ermöglicht maschinennahe Programmierung (Stichw. „Zeiger“), als auch abstrakte Programmierung (i.e. Objektorientierung)  Kompilierung über g++ Compiler, Microsoft Visual C++ Compiler, etc.
  • 45.
    Objektorientierte Programmiersprachen: Java Java  Besonderheit: Java-Programme werden in Bytecode übersetzt, anschließend in einer Java-Laufzeitumgebung ausgeführt  Virtuelle Maschine (VM)  Vorteil: Plattformunabhängigkeit: Java-Programme laufen (zumeist) ohne weitere Anpassungen auf unterschiedlichen Computer- und Betriebssystemen, für die eine Java-VM existiert
  • 46.

Hinweis der Redaktion

  • #8 Dimmu Borgir = Dunkle Burgen, Dunkle Städte
  • #12 Analyse des gestellten Problems  ToDo: Eine Möglichkeit entwickeln, trotz Dunkelheit einen Weg aus dem Labyrinth zu finden Spezifikation: Problembeschreibung – im Gegensatz zum Algorithmus, der die Lösung des Problems angibt Beachten: Problemkomplex exakt und vollständig beschreiben Ein- und Ausgabewerte berücksichtigen (Parameter) Randbedingungen bzw. Spezialfälle berücksichtigen
  • #17 Terminierung von Algorithmen Wir verlangen (zumeist) von Algorithmen, dass sie terminieren, d.h. dass sie in endlicher Zeit (und möglichst schnell  Performance) ihre Arbeit erledigt haben Performanz: Geschwindigkeit der Problemlösung
  • #18 Terminierung von Algorithmen Wir verlangen (zumeist) von Algorithmen, dass sie terminieren, d.h. dass sie in endlicher Zeit (und möglichst schnell  Performance) ihre Arbeit erledigt haben Performanz: Geschwindigkeit der Problemlösung
  • #19 Grundfrage Algorithmus: Existiert ein Algorithmus, der für jedes denkbare Labyrinth, aus dem es einen Ausgang gibt, einen Weg ins Freie findet?
  • #23 Programmiersprache: Eine zum Formulieren von Programmen geschaffene künstliche / formale Sprache Warum braucht man so etwas? Darum:
  • #25 compiler interpreter
  • #28 Wer prüft zu welchem Zeitpunkt die Grammatik? Programmierung häufig mittels Programmierumgebungen (IDE, integrated develompent environment), die Werkzeuge beinhalten: Editor Compiler Debugger (Fehlersuche) Beispiele: Microsoft Visual Studio, Qt Creator, Eclipse Compiler  Computerprogramm, das ein in einer Hochsprache (C++, etc.) formuliertes Programm, das sog. Quellprogramm in ein Zielprogramm, z.B.: Bytecode (Sammlung von Befehlen für eine virtuelle Maschine) oder Maschinencode (Instruktionen, die der entsprechende Prozessor (Hardware) direkt umsetzen kann) übersetzt Compiler / compilierte Sprachen kompletter Programmtext wird in eine Folge von Maschinenbefehlen übersetzt, bevor die erste Programmanweisung ausgeführt wird. [C++] Interpreter / interpretierte Sprachen übersetzt immer nur eine einzige Programmanweisung in ein kleines Unterprogramm aus Maschinenbefehlen und führt dieses sofort aus. Anschließend wird mit der nächsten Anweisung genauso verfahren. [JavaScript, Python] Interpreter Pro: Einfacher zu konstruieren als Compiler Interpreter Contra: Ein Befehl, der mehrfach ausgeführt wird, muss jedes mal erneut übersetzt werden
  • #30 Dynamische Typisierung Paradigmen: Prozedurale, funktionale und objektorientierte (klassenlose) Programmierung
  • #35 Doppelte Genauigkeit…?!?  Kollisionserkennung / Problem: „Clipping“
  • #37 Funktionale Programmierung: Programme bestehen aus Funktionen.
  • #38 Objektzustand umfasst die Attribute und jeweilige Verbindungen zu anderen Objekten Attribute: unveränderliche Merkmale des Objekts; die Attributwerte können Änderungen unterliegen Verhalten eines Objekts wird durch eine Menge von Operationen beschrieben; Änderung oder Abfrage des Zustandes ausschließlich durch Operationen
  • #46 Vererbung beschreibt eine Beziehung zwischen einer allgemeinen Klasse (Basisklasse) und einer spezialisierten Klasse. Die spezialisierte Klasse ist vollständig konsistent mit der Basisklasse, enthält aber zusätzliche Informationen (Attribute, Operationen). Die allgemeine Klasse wird auch als Oberklasse (engl. super class), die spezialisierte Klasse als Unterklasse (engl. sub class) bezeichnet. Das Konzept der Vererbung ist nicht nur dazu gedacht, um gemeinsame Eigenschaften und Verhaltensweisen zusammenzufassen, sondern sie muss immer auch eine Generalisierung bzw. Spezialisierung darstellen, d.h. jedes Objekt der Unterklasse "ist ein" Objekt der Oberklasse.
  • #51 Überprüfung, ob das entwickelte Programm die Problemstellung korrekt und vollständig löst Dazu: Ausführung des Programmes mit verschiedenen Eingabewerten und Startzuständen, um möglichst jede Situation abzubilden Automatisierte Tests  “Writing automated tests is accepted to produce higher quality code at lower cost. More tests == less time spent debugging”