Benutzerdefinierte Komponenten implementieren
Um benutzerdefinierte Komponenten zu implementieren, verwenden Sie das Oracle Digital Assistant Node.js-SDK für die Schnittstelle mit dem benutzerdefinierten Komponentenservice von Digital Assistant.
So implementieren Sie benutzerdefinierte Komponenten, die Sie im eingebetteten Container von Digital Assistant, in Oracle Cloud Infrastructure Functions, in einem Mobile Hub-Backend oder auf einem Node.js-Server bereitstellen können:
Wenn Sie das benutzerdefinierte Komponentenpackage in einem eingebetteten benutzerdefinierten Komponentenservice bereitstellen möchten, zählt jeder Skill, dem Sie das Package hinzufügen, als separater Service. Die zulässige Anzahl eingebetteter benutzerdefinierter Komponentenservices einer Instanz ist begrenzt. Wenn Sie das Limit nicht kennen, bitten Sie den Serviceadministrator, den Parameter
embedded-custom-component-service-count
für Sie abzurufen, wie unter Servicelimits in der Infrastructure-Konsole anzeigen beschrieben. Ziehen Sie in Erwägung, mehrere Komponenten pro Package zu verpacken, um die Anzahl der von Ihnen verwendeten eingebetteten Komponentenservices zu minimieren. Wenn Sie versuchen, einen Komponentenservice hinzuzufügen, nachdem Sie dieses Limit erreicht haben, verläuft das Erstellen des Service nicht erfolgreich.
Schritt 1: Software für das Erstellen von benutzerdefinierten Komponenten installieren
Zur Erstellung eines benutzerdefinierten Komponentenpackages benötigen Sie Node.js, Node Package Manager und das Oracle Digital Assistant Bots-Node.js-SDK.
Unter Windows funktioniert das Bots-Knoten-SDK nicht unter Windows, wenn die Knoteninstallation Version 20.12.2 oder höher ist, da eine abwärtsinkompatible Änderung in Node.js vorliegt. Wenn die Node-Version 20.12.2 oder höher bereits installiert ist, müssen Sie sie deinstallieren und dann Version 20.12.1 oder eine frühere Version installieren, damit das Bots Node SDK funktioniert.
Schritt 2: Benutzerdefiniertes Komponentenpackage erstellen
Um ein Projekt zu starten, verwenden Sie den Befehl bots-node-sdk init
über die Befehlszeilenschnittstelle (CLI) des SDK, um die erforderlichen Dateien und die Verzeichnisstruktur für die Komponentenstruktur zu erstellen.
Der Befehl init
bietet einige Optionen, z.B. zur Verwendung von JavaScript (Standard) oder TypeScript sowie zur Angabe des Namens der JavaScript-Datei der anfänglichen Komponente. Diese Optionen werden unter CLI-Entwicklertools beschrieben. Nachfolgend finden Sie den Basisbefehl zum Starten eines JavaScript-Projekts:
bots-node-sdk init <top-level folder path> --name <component service name>
Dieser Befehl führt die folgenden Aktionen für ein JavaScript-Package aus:
-
Erstellt den Ordner der obersten Ebene.
-
Erstellt einen
components
-Ordner und fügt eine JavaScript-Beispielkomponentendatei mit dem Namenhello.world.js
hinzu. Hier speichern Sie Ihre JavaScript-Komponentendateien. -
Fügt eine
package.json
-Datei hinzu, diemain.js
als Haupteinstiegspunkt angibt und@oracle/bots-node-sdk
alsdevDependency
auflistet. Die Packagedatei verweist auch auf einigebots-node-sdk
-Skripte.{ "name": "myCustomComponentService", "version": "1.0.0", "description": "Oracle Bots Custom Component Package", "main": "main.js", "scripts": { "bots-node-sdk": "bots-node-sdk", "help": "npm run bots-node-sdk -- --help", "prepack": "npm run bots-node-sdk -- pack --dry-run", "start": "npm run bots-node-sdk -- service ." }, "repository": {}, "dependencies": {}, "devDependencies": { "@oracle/bots-node-sdk": "^2.2.2", "express": "^4.16.3" } }
-
Fügt eine
main.js
-Datei hinzu, die die Packageeinstellungen exportiert und auf den Komponentenordner für den Speicherort der Komponenten und den Ordner der obersten Ebene verweist. -
Fügt dem Ordner der obersten Ebene eine
.npmignore
-Datei hinzu. Diese Datei wird verwendet, wenn Sie das Komponentenpackage exportieren. Sie muss.tgz
-Dateien aus dem Package ausschließen. Beispiel:*.tgz
. -
Bei einigen Versionen von npm wird eine
package-lock.json
-Datei erstellt. - Installiert alle Packageabhängigkeiten im Unterordner
node_modules
.
Wenn Sie den Packageordner nicht mit dem Befehl
bots-node-sdk init
erstellen, stellen Sie sicher, dass der Ordner der obersten Ebene eine .npmignore
-Datei mit einem *.tgz
-Eintrag enthält. Beispiel:*.tgz
spec
service-*
Andernfalls fügen Sie jedes Mal, wenn Sie die Dateien in eine TGZ-Datei verpacken, die TGZ-Datei ein, die bereits im Ordner der obersten Ebene vorhanden ist, sodass Ihre TGZ-Datei kontinuierlich ihre Größe verdoppelt.
Wenn Sie das Deployment im eingebetteten Container planen, muss das Package mit Knoten 14.17.0 kompatibel sein.
Schritt 3: Benutzerdefinierte Komponente erstellen
Nachfolgend werden die Schritte zum Erstellen der einzelnen benutzerdefinierten Komponenten in Ihrem Package aufgeführt:
Komponentendatei erstellen
Mit dem CLI-Befehl init component
des SDK können Sie eine JavaScript- oder TypeScript-Datei mit dem Framework erstellen. Dann können Sie mit dem Node.js-SDK von Oracle Digital Assistant eine benutzerdefinierte Komponente schreiben. Die Sprache, die Sie beim Ausführen des init
-Befehls zum Erstellen des Komponentenpackages angegeben haben, bestimmt, ob eine JavaScript- oder TypeScript-Datei erstellt wird.
Beispiel: Um eine Datei für die benutzerdefinierte Komponente zu erstellen, wechseln Sie in einem Terminalfenster mit CD zum Ordner der obersten Ebene des Packages, und geben Sie den folgenden Befehl ein. Ersetzen Sie dabei <component name>
durch den Namen der Komponente:
bots-node-sdk init component <component name> c components
Bei JavaScript fügt dieser Befehl <component name>.js
zum components
-Ordner hinzu. Bei TypeScript wird die Datei dem Ordner src/components
hinzugefügt. Das Argument c
gibt an, dass die Datei für eine benutzerdefinierte Komponente gilt.
Beachten Sie, dass der Komponentenname nicht länger als 100 Zeichen sein darf. Sie können nur alphanumerische Zeichen und Unterstriche im Namen verwenden. Bindestriche sind nicht zulässig. Der Name darf auch nicht das Präfix System.
aufweisen. Oracle Digital Assistant lässt nicht zu, dass Sie einen benutzerdefinierten Komponentenservice mit ungültigen Komponentennamen hinzufügen.
Weitere Details finden Sie unter https://github.com/oracle/bots-node-sdk/blob/master/bin/CLI.md
.
Code zu Metadaten hinzufügen und Funktionen aufrufen
Die benutzerdefinierte Komponente muss zwei Objekte exportieren:
metadata
: Gibt die folgenden Komponenteninformationen für den Skill an.- Komponentenname
- Unterstützte Eigenschaften
- Unterstützte Übergangsaktionen
Bei YAML-basierten Dialogabläufen unterstützt die benutzerdefinierte Komponente standardmäßig die folgenden Eigenschaften. Diese Eigenschaften sind für Skills, die im visuellen Dialogmodus entworfen wurden, nicht verfügbar.
autoNumberPostbackActions
: Boolescher Wert. Nicht erforderlich. Beitrue
werden Schaltflächen und Listenoptionen automatisch nummeriert. Der Standardwert istfalse
. Siehe Automatische Nummerierung von Nur-Text-Kanälen in YAML-Dialogabläufen.insightsEndConversation
: Boolescher Wert. Nicht erforderlich. Beitrue
wird die Aufzeichnung der Unterhaltung für Insight-Berichte gestoppt. Der Standardwert istfalse
. Siehe Dialogablauf modellieren.insightsInclude
: Boolescher Wert. Nicht erforderlich. Beitrue
wird der Status in Insight-Berichte einbezogen. Der Standardwert isttrue
. Siehe Dialogablauf modellieren.translate
: Boolescher Wert. Nicht erforderlich. Beitrue
ist die automatische Übersetzung für diese Komponente aktiviert. Der Standardwert ist der Wert der Kontextvariablenautotranslation
. Siehe Übersetzungsservices in Skills.
invoke
: Enthält die auszuführende Logik. Bei dieser Methode können Sie Skillkontextvariablen lesen und schreiben, Unterhaltungsnachrichten erstellen, Statusübergänge festlegen, REST-Aufrufe tätigen usw. Normalerweise würden Sie das Schlüsselwortasync
mit dieser Funktion verwenden, um Promises zu verarbeiten. Die Funktioninvoke
akzeptiert das folgende Argument:context
mit Angabe der Referenz zum ObjektCustomComponentContext
im Node.js-SDK von Digital Assistant. Diese Klasse wird in der SDK-Dokumentation unter https://oracle.github.io/bots-node-sdk/ beschrieben. In früheren Versionen des SDK lautete der Nameconversation
. Sie können einen der beiden Namen verwenden.
Hinweis
Wenn Sie eine JavaScript-Bibliothek verwenden, die keine Promises unterstützt (und daher nicht das Schlüsselwortasync
verwendet), können Sie auch eindone
-Argument als Callback hinzufügen, das die Komponente aufruft, wenn die Verarbeitung abgeschlossen ist.
Beispiel:
'use strict';
module.exports = {
metadata: {
name: 'helloWorld',
properties: {
human: { required: true, type: 'string' }
},
supportedActions: ['weekday', 'weekend']
},
invoke: async(context) => {
// Retrieve the value of the 'human' component property.
const { human } = context.properties();
// determine date
const now = new Date();
const dayOfWeek = now.toLocaleDateString('en-US', { weekday: 'long' });
const isWeekend = [0, 6].indexOf(now.getDay()) > -1;
// Send two messages, and transition based on the day of the week
context.reply(`Greetings ${human}`)
.reply(`Today is ${now.toLocaleDateString()}, a ${dayOfWeek}`)
.transition(isWeekend ? 'weekend' : 'weekday');
}
}
Weitere Informationen und einige Codebeispiele finden Sie unter Benutzerdefinierte Komponenten schreiben in der Dokumentation zum Bots Node-SDK.
Ablauf mit "keepTurn" und "transition" steuern
Sie verwenden verschiedene Kombinationen der Bots Node SDK-Funktionen keepTurn
und transition
, um zu definieren, wie die benutzerdefinierte Komponente mit einem Benutzer interagiert und wie die Unterhaltung fortgesetzt wird, nachdem die Komponente die Ablaufsteuerung wieder an den Skill übergeben hat.
-
keepTurn(boolean)
gibt an, ob die Unterhaltung in einen anderen Status übergehen soll, ohne den Benutzer zuerst zur Eingabe aufzufordern.Wenn Sie
keepTurn
auf "true" setzen möchten, sollten SiekeepTurn
nachreply
aufrufen, weilreply
diekeepTurn
-Funktion implizit auffalse
setzt. -
transition(action)
bewirkt, dass der Dialog nach dem Senden aller etwaiger Antworten in den nächsten Status übergeht. Das optionaleaction
-Argument benennt die jeweilige von der Komponente zurückgegebene Aktion (Ergebnis).Wenn Sie
transition()
nicht aufrufen, wird die Antwort gesendet, der Dialog bleibt jedoch im Status, und die nachfolgende Benutzereingabe kehrt zu dieser Komponente zurück. Das bedeutet, dassinvoke()
erneut aufgerufen wird.
invoke: async (context) ==> {
...
context.reply(payload);
context.keepTurn(true);
context.transition ("success");
}
Im Folgenden finden Sie einige häufige Anwendungsfälle, in denen Sie den Dialogablauf mit keepTurn
und transition
steuern können:
Anwendungsfall | Für keepTurn und transition festgelegte Werte |
---|---|
Eine benutzerdefinierte Komponente, die in einen anderen Status übergeht, ohne den Benutzer zuerst zur Eingabe aufzufordern. |
Beispiel: Diese benutzerdefinierte Komponente aktualisiert eine Variable mit einer Werteliste, die sofort im nächsten Status im Dialogablauf angezeigt werden soll.
|
Eine benutzerdefinierte Komponente, mit der der Skill auf die Eingabe warten kann, nachdem die Steuerung an ihn zurückgegeben wurde und bevor er in einen anderen Status übergeht. |
Beispiel:
|
Eine benutzerdefinierte Komponente, die Benutzereingaben abruft, ohne die Ablaufsteuerung wieder an den Skill zurückzugeben. Beispiel:
|
Beispiel: Diese benutzerdefinierte Komponente gibt ein Angebot aus und zeigt dann die Schaltflächen
Yes und No an, um ein anderes Angebot anzufordern. Wenn der Benutzer auf No klickt, kehrt die Komponente zum Skill zurück.
Wenn eine Komponente nicht in einen anderen Status übergeht, muss sie ihren eigenen Status verfolgen, wie im obigen Beispiel gezeigt. Für eine komplexere Statusverarbeitung, damit der Benutzer beispielsweise die Möglichkeit erhält, einen Datenabruf abzubrechen, wenn dieser zu lange dauert, können Sie eine Kontextvariable erstellen und verwenden. Beispiel: Hinweis: Solange kein Übergang stattfindet, sind alle Werte verfügbar, die als Komponenteneigenschaften übergeben werden. |
Der Komponentenaufruf wird ohne Benutzereingabe wiederholt. Beispiel:
|
Nachfolgend finden Sie ein etwas gekünsteltes Beispiel, das zeigt, wie der Aufruf wiederholt wird, ohne auf Benutzereingaben zu warten, und wie anschließend der Übergang erfolgt:
|
Auf das Backend zugreifen
Es gibt mehrere Node.js-Librarys, die erstellt wurden, um HTTP-Anforderungen einfach zu machen, und die Liste wird häufig geändert. Sie sollten die Vor- und Nachteile der aktuell verfügbaren Librarys überprüfen und entscheiden, welche für Sie am besten geeignet ist. Wir empfehlen, eine Library zu verwenden, die Promises unterstützt, damit Sie die async
-Version der invoke
-Methode, die in Version 2.5.1 eingeführt wurde, nutzen und mit dem await
-Schlüsselwort synchron REST-Aufrufe schreiben können.
Eine Option ist die node fetch-API, die mit dem Bots Node-SDK vorinstalliert ist. Unter Zugriff auf das Backend mit HTTP-REST-Aufrufen in der Dokumentation für das Bots Node-SDK finden Sie einige Codebeispiele.
SDK für den Zugriff auf Anforderungs- und Antwort-Payloads verwenden
Mit CustomComponentContext
-Instanzmethoden können Sie den Kontext für den Aufruf abrufen, Variablen anzeigen und ändern und Ergebnisse an die Dialog-Engine zurücksenden.
Codebeispiele zur Verwendung dieser Methoden finden Sie unter Benutzerdefinierte Komponenten schreiben und Unterhaltungsmessaging in der Dokumentation des Bots Node-SDK.
Die SDK-Referenzdokumentation finden Sie unter https://github.com/oracle/bots-node-sdk
.
Benutzerdefinierte Komponenten für mehrsprachige Skills
Wenn Sie eine benutzerdefinierte Komponente entwerfen, sollten Sie überlegen, ob die Komponente von einem Skill verwendet wird, der mehrere Sprachen unterstützt.
Wenn die benutzerdefinierte Komponente mehrsprachige Skills unterstützen muss, müssen Sie wissen, ob die Skills für die native Sprachunterstützung oder den Übersetzungsservice konfiguriert sind.
Wenn Sie einen Übersetzungsservice verwenden, können Sie den Text aus dem Skill übersetzen. Sie haben folgende Optionen:
-
Setzen Sie die Eigenschaft
translate
im Status der benutzerdefinierten Komponente auf "true", um die Antwort der Komponente zu übersetzen, wie unter Antworten direkt an den Übersetzungsservice senden beschrieben. -
Senden Sie Rohdaten an den Skill in Variablen zurück, und verwenden Sie die Werte der Variablen in einer Systemkomponente, aus der die Ausgabe besteht. Setzen Sie die Eigenschaft
translate
dieser Komponente auf "true". Siehe Systemkomponente zum Übergeben der Nachricht an den Übersetzungsservice verwenden. -
Senden Sie Rohdaten an den Skill in Variablen zurück, und verwenden Sie die Variablenwerte in einer Systemkomponente, die den Resource Bundle-Schlüssel für die Sprache verwendet. Siehe Resource Bundle mit einer Systemkomponente referenzieren.
Für Sprachkenntnisse in Muttersprache stehen Ihnen folgende Optionen zur Verfügung:
-
Übergeben Sie die Daten an den Skill in Variablen, und geben Sie dann den Text aus einer Systemkomponente aus, indem Sie die Werte der Variablen an einen Resource Bundle-Schlüssel übergeben, wie unter Systemkomponente zum Referenzieren eines Resource Bundles verwenden beschrieben. Mit dieser Option muss die benutzerdefinierte Komponente Metadateneigenschaften aufweisen, damit der Skill die Namen der Variablen zum Speichern der Daten übergeben kann.
-
Verwenden Sie das Resource Bundle aus der benutzerdefinierten Komponente, um die Antwort der benutzerdefinierten Komponente zu verfassen, wie unter Resource Bundles aus der benutzerdefinierten Komponente referenzieren beschrieben. Mit der Methode
conversation.translate()
rufen Sie die Resource Bundle-Zeichenfolge ab, die für Ihren Aufruf voncontext.reply()
verwendet werden soll. Diese Option ist nur für Resource Bundle-Definitionen gültig, die positionale (nummerierte) Parameter verwenden. Es funktioniert nicht für benannte Parameter. Bei dieser Option muss die benutzerdefinierte Komponente eine Metadateneigenschaft für den Namen des Resource Bundle-Schlüssels aufweisen, und die Parameter des benannten Resource Bundle-Schlüssels müssen mit denen übereinstimmen, die beim Aufruf voncontext.reply()
verwendet werden.
Im Folgenden finden Sie ein Beispiel für die Verwendung des Resource Bundles aus der benutzerdefinierten Komponente. In diesem Beispiel würde fmTemplate
auf ${rb('date.dayOfWeekMessage', 'lundi', '19 juillet 2021')}
gesetzt.
'use strict';
var IntlPolyfill = require('intl');
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
module.exports = {
metadata: () => ({
name: 'Date.DayOfWeek',
properties: {
rbKey: { required: true, type: 'string' }
},
supportedActions: []
}),
invoke: (context, done) => {
const { rbKey } = context.properties();
if (!rbKey || rbKey.startsWith('${')){
context.transition();
done(new Error('The state is missing the rbKey property or it uses an invalid expression to pass the value.'));
}
//detect user locale. If not set, define a default
const locale = context.getVariable('profile.locale') ?
context.getVariable('profile.locale') : 'en-AU';
const jsLocale = locale.replace('_','-');
//when profile languageTag is set, use it. If not, use profile.locale
const languageTag = context.getVariable('profile.languageTag')?
context.getVariable('profile.languageTag') : jslocale;
/* =============================================================
Determine the current date in local format and
the day name for the locale
============================================================= */
var now = new Date();
var dayTemplate = new Intl.DateTimeFormat(languageTag,
{ weekday: 'long' });
var dayOfWeek = dayTemplate.format(now);
var dateTemplate = new Intl.DateTimeFormat(languageTag,
{ year: 'numeric', month: 'long', day: 'numeric'});
var dateToday = dateTemplate.format(now);
/* =============================================================
Use the context.translate() method to create the ${Freemarker}
template that's evaluated when the reply() is flushed to the
client.
============================================================= */
const fmTemplate = context.translate(rbKey, dateToday, dayOfWeek );
context.reply(fmTemplate)
.transition()
.logger().info('INFO : Generated FreeMarker => '
+ fmTemplate);
done();
}
};
Sicherstellen, dass die Komponente in digitalen Assistenten funktioniert
In einer Unterhaltung über den digitalen Assistenten kann ein Benutzer den Unterhaltungsablauf unterbrechen, indem er den Betreff ändert. Beispiel: Wenn ein Benutzer einen Ablauf zum Kauf startet, kann er diesen Ablauf unterbrechen, um abzufragen, wie viel Guthaben er noch auf einer Geschenkkarte hat. Wir bezeichnen dies als nicht sequenzielle Abfolge. Damit der digitale Assistent nicht folgerichtige Abfolgen identifizieren und verarbeiten kann, rufen Sie die context.invalidInput(payload)
-Methode auf, wenn eine Benutzeräußerungsantwort im Kontext der Komponente nicht verstanden wird.
In einer digitalen Unterhaltung bestimmt die Laufzeit, ob eine ungültige Eingabe eine nicht sequenzielle Abfolge ist, indem in allen Skills nach Antwortübereinstimmungen gesucht wird. Wenn sie Übereinstimmungen findet, wird der Ablauf umgeleitet. Andernfalls wird die Meldung angezeigt (sofern vorhanden), der Benutzer wird zur Eingabe aufgefordert, und die Komponente wird erneut ausgeführt. Die neue Eingabe wird an die Komponente in der Eigenschaft text
übergeben.
In einer Unterhaltung mit einem Standalone-Skill zeigt die Laufzeit die Nachricht an (sofern vorhanden), fordert den Benutzer zur Eingabe auf und führt die Komponente erneut aus. Die neue Eingabe wird an die Komponente in der Eigenschaft text
übergeben.
Dieser Beispielcode ruft context.invalidInput(payload)
auf, wenn die Eingabe keine Zahl ist.
"use strict"
module.exports = {
metadata: () => ({
"name": "AgeChecker",
"properties": {
"minAge": { "type": "integer", "required": true }
},
"supportedActions": [
"allow",
"block",
"unsupportedPayload"
]
}),
invoke: (context, done) => {
// Parse a number out of the incoming message
const text = context.text();
var age = 0;
if (text){
const matches = text.match(/\d+/);
if (matches) {
age = matches[0];
} else {
context.invalidUserInput("Age input not understood. Please try again");
done();
return;
}
} else {
context.transition('unsupportedPayload");
done();
return;
}
context.logger().info('AgeChecker: using age=' + age);
// Set action based on age check
let minAge = context.properties().minAge || 18;
context.transition( age >= minAge ? 'allow' : 'block' );
done();
}
};
Nachfolgend finden Sie ein Beispiel dafür, wie ein digitaler Assistent ungültige Eingaben zur Laufzeit verarbeitet. Für die erste Altersantwort (twentyfive
) gibt es keine Übereinstimmungen in den Skills, die beim digitalen Assistenten registriert sind. Die Unterhaltung zeigt also die angegebene Nachricht context.invalidUserInput
an. In der zweiten Altersantwort (Geld senden
) findet der digitale Assistent eine Übereinstimmung, sodass er fragt, ob an diesen Ablauf umgeleitet werden soll.

Beschreibung der Abbildung Components-nonsequitur-conversation.png
Rufen Sie entweder context.invalidInput()
oder context.transition()
auf. Wenn Sie beide Vorgänge aufrufen, stellen Sie sicher, dass die Variable system.invalidUserInput
noch festgelegt ist, wenn zusätzliche Nachrichten gesendet werden. Beachten Sie auch, dass Benutzereingabekomponenten (wie Common Response- und Resolve-Entity-Komponenten) system.invalidUserInput
zurücksetzen.
Beispiel: Die AgeChecker-Komponente wird wie unten dargestellt geändert, und context.transition()
wird nach context.invalidInput()
aufgerufen.
if (matches) { age = matches[0]; } else {
context.invalidUserInput("Age input not understood. Please try again");
context.transition("invalid");
context.keepTurn(true);
done();
return;
}
In diesem Fall muss der Datenfluss wieder zu askage
übergehen, sodass der Benutzer zwei Ausgabenachrichten erhält: "Altersangabe nicht verstanden. Bitte versuchen Sie es erneut", gefolgt von "Wie alt sind Sie?". So kann das in einem Dialogablauf im YAML-Modus behandelt werden.
askage:
component: "System.Output"
properties:
text: "How old are you?"
transitions:
next: "checkage"
checkage:
component: "AgeChecker"
properties:
minAge: 18
transitions:
actions:
allow: "crust"
block: "underage"
invalid: "askage"
Komponentenservice in einer Entwicklungsumgebung ausführen
Während der Entwicklungsphase können Sie einen lokalen Service starten, um das benutzerdefinierte Komponentenpackage verfügbar zu machen.