Die Verwendung einer REST-API wie COTOHA API erfordert drei Prozesse.
Davon im vorherigen Artikel (Versuchen Sie, die COTOHA-API-Syntaxanalyse in Java zu verwenden) Ich habe die Verarbeitung entsprechend 1. (Erstellen) und 2. (Senden) durchgeführt, aber da die Antwort als einfacher JSON belassen wurde, werde ich sie einer Java-Klasse zuordnen.
DefaultKeywordWithDependency ist ein Modell, das die Abhängigkeit in NLP4J implementiert, die ich mit DIY erstelle /nlp4j/blob/master/nlp4j/nlp4j-core/src/main/java/nlp4j/impl/DefaultKeywordWithDependency.java) Ich habe eine Klasse, daher werde ich sie dort zuordnen. (Da es → ist, wird es nicht einfach der POJO-Klasse zugeordnet.)
DefaultKeywordWithDependency https://github.com/oyahiroki/nlp4j/blob/master/nlp4j/nlp4j-core/src/main/java/nlp4j/impl/DefaultKeywordWithDependency.java
Parser
Der JSON des Syntaxanalyseergebnisses sieht wie folgt aus. Das Ergebnis der Syntaxanalyse sind baumartige Daten, aber es kann gelesen werden, dass es sich im Sinne von JSON nicht um einen Baum handelt.
{
"result": [
{
"chunk_info": {"id": 0,"head": 2,"dep": "D","chunk_head": 0,"chunk_func": 1,
"links": []
},
"tokens": [
{
"id": 0,"form": "heute","kana": "heute","lemma": "heute","pos": "Substantiv",
"features": ["Datum (und Uhrzeit"],
"dependency_labels": [{"token_id": 1,"label": "case"}],
"attributes": {}
},
{
"id": 1,"form": "Ist","kana": "C.","lemma": "Ist","pos": "Aufeinanderfolgende Hilfswörter",
"features": [],
"attributes": {}
}
]
},
{...(Abkürzung)...},
{...(Abkürzung)...}
]
}
],
"status": 0,
"message": ""
}
Unten ist die Klasse für Perth. (Der gesamte Code wird auf Maven Repository und Github veröffentlicht.)
package nlp4j.cotoha;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import nlp4j.Keyword;
import nlp4j.impl.DefaultKeyword;
import nlp4j.impl.DefaultKeywordWithDependency;
/**
*COTOHA API analysiert V1-Antwort-JSON
*
* @author Hiroki Oya
* @since 1.0.0.0
*
*/
public class CotohaNlpV1ResponseHandler {
static private final Logger logger = LogManager.getLogger(MethodHandles.lookup().lookupClass());
/**
*Schlüsselwörter, die als Wurzel der Syntax extrahiert wurden
*/
ArrayList<DefaultKeywordWithDependency> roots = new ArrayList<>();
/**
*Liste der Schlüsselwörter
*/
ArrayList<Keyword> keywords = new ArrayList<>();
/**
*Ursprüngliches Schlüsselwort für Phrase
*/
ArrayList<Keyword> chunkLinkKeywords = new ArrayList<>();
/**
* @Rückgabeklausel Ursprüngliches Schlüsselwort
*/
public ArrayList<Keyword> getChunkLinkKeywords() {
return chunkLinkKeywords;
}
/**
*Quelle
*/
ArrayList<String> chunkLinks = new ArrayList<>();
/**
*Quelle
*/
JsonArray arrChunkLinks = new JsonArray();
/**
* Map: token_id --> Keyword
*/
HashMap<String, DefaultKeywordWithDependency> mapTokenidKwd = new HashMap<>();
/**
* Map: id --> Keyword
*/
HashMap<String, DefaultKeywordWithDependency> mapIdKwd = new HashMap<>();
/**
* token id --> sentence
*/
HashMap<Integer, Integer> idSentenceMap = new HashMap<>();
/**
*Abhängige Schlüsselwörter
*/
ArrayList<DefaultKeyword> patternKeywords = new ArrayList<>();
/**
* @Kakemoto zurückgeben
*/
public JsonArray getArrChunkLinks() {
return arrChunkLinks;
}
/**
* @Kakemoto zurückgeben
*/
public ArrayList<String> getChunkLinks() {
return chunkLinks;
}
/**
* @Karte der Rückgabe-ID und Schlüsselwörter
*/
public HashMap<String, DefaultKeywordWithDependency> getIdMapKwd() {
return mapIdKwd;
}
/**
* @return Zuordnung von Formularelement-ID und Satznummer
*/
public HashMap<Integer, Integer> getIdSentenceMap() {
return idSentenceMap;
}
/**
* @Wortfolge zurückgeben
*/
public ArrayList<Keyword> getKeywords() {
return keywords;
}
/**
* @Karte der Rückkehr TOKEN ID und Schlüsselwörter
*/
public HashMap<String, DefaultKeywordWithDependency> getMapKwd() {
return mapTokenidKwd;
}
/**
* @Kakeke-Schlüsselwort zurückgeben
*/
public ArrayList<DefaultKeyword> getPatternKeywords() {
return patternKeywords;
}
/**
* @return Extrahiertes Abhängigkeitsroutenschlüsselwort
*/
public ArrayList<DefaultKeywordWithDependency> getRoots() {
return roots;
}
/**
* @param json COTOHA API Syntax-Parsing-Antwort JSON
*/
public void parse(String json) {
// JSON Parser
Gson gson = new Gson();
// COTOHA API RESPONSE
JsonObject result = gson.fromJson(json, JsonObject.class);
//Die Reihenfolge, in der sie im Satz erscheinen
int sequence = 0;
// {
// "result":[
// _{"chunk_info":{...},"tokens"[{...},{...},{...}]},
// _{"chunk_info":{...},"tokens"[{...},{...},{...}]},
// _{"chunk_info":{...},"tokens"[{...},{...},{...}]}
// ]
// }
// chunk_Ein Objekt, das Informationen und Token kombiniert
JsonArray arrChunkTokens = result.getAsJsonArray("result");
int idxBegin = 0;
int idxSentence = 0;
// FOR EACH(chunk_tokens)
for (int idxChunkTokens = 0; idxChunkTokens < arrChunkTokens.size(); idxChunkTokens++) {
JsonObject chunk_token = arrChunkTokens.get(idxChunkTokens).getAsJsonObject();
// 1. chunk_Info-Klausel Informationsobjekt
// https://api.ce-cotoha.com/contents/reference/apireference.html#parsing_response_chunk
JsonObject chunk_info = chunk_token.get("chunk_info").getAsJsonObject();
logger.debug("chunk_info: " + chunk_info);
int chunk_head = -1;
{
//Morphologische Elementnummer (0 Ursprung)
String chunk_id = "" + chunk_info.get("id").getAsInt();
//Kontaktphrasennummer
chunk_head = chunk_info.get("head").getAsInt();
//Anordnung der Quellinformationen
// https://api.ce-cotoha.com/contents/reference/apireference.html#parsing_response_links
JsonArray links = chunk_info.get("links").getAsJsonArray();
for (int n = 0; n < links.size(); n++) {
JsonObject link = links.get(n).getAsJsonObject();
int link_link = link.get("link").getAsInt();
String link_label = link.get("label").getAsString();
chunkLinks.add(chunk_id + "/" + link_label + "/" + link_link);
arrChunkLinks.add(link);
}
}
// 2.Token Morphologisches Informationsobjekt
// https://api.ce-cotoha.com/contents/reference/apireference.html#parsing_response_morpheme
JsonArray tokens = chunk_token.get("tokens").getAsJsonArray();
//FÜR JEDE MARKE Morphologisches Informationsobjekt
for (int idxTokens = 0; idxTokens < tokens.size(); idxTokens++) {
JsonObject token = tokens.get(idxTokens).getAsJsonObject();
logger.debug("token: " + token);
// X-Y-Stil ID Welches morphologische Element in einer Klausel
String token_id = idxChunkTokens + "-" + idxTokens;
logger.debug("token_id: " + token_id);
String token_pos = token.get("pos") != null ? token.get("pos").getAsString() : null;
String token_lemma = token.get("lemma") != null ? token.get("lemma").getAsString() : null;
String token_form = token.get("form") != null ? token.get("form").getAsString() : null;
String token_kana = token.get("kana") != null ? token.get("kana").getAsString() : null;
//Ist es der letzte der Token? Wenn true, ist das Ziel der Abhängigkeit das nächste Token
boolean isLastOfTokens = (idxTokens == tokens.size() - 1);
if (isLastOfTokens) {
logger.debug("Letzter Token: chunk_head:" + chunk_head);
}
//Abhängige Schlüsselwörter(In nlp4j definiert)
DefaultKeywordWithDependency kw = new DefaultKeywordWithDependency();
//Seriennummern in der Reihenfolge, in der sie im Text erscheinen
kw.setSequence(sequence);
sequence++;
//Startposition
kw.setBegin(idxBegin);
// lemma:Stichwort:Prototyp
if (token_lemma != null) {
kw.setLex(token_lemma);
} else {
logger.warn("lemma is null");
}
int intId = token.get("id").getAsInt();
String id = "" + token.get("id").getAsInt();
idSentenceMap.put(intId, idxSentence);
//Ob es das Ende eines Satzes ist
boolean isLastOfSentence = (chunk_head == -1 && idxTokens == tokens.size() - 1) //
|| (token_pos != null && token_pos.equals("Phrase"));
// IF(Ende des Satzes)
if (isLastOfSentence) {
//Inkrement-Anweisungsnummer
idxSentence++;
}
//Set Facettenteil Texte
kw.setFacet(token_pos);
//setze den Ausdruckstyp str
kw.setStr(token_form);
kw.setEnd(idxBegin + kw.getStr().length());
idxBegin += kw.getStr().length();
//Lesung einstellen Lesen
kw.setReading(token_kana);
mapTokenidKwd.put(token_id, kw);
mapIdKwd.put(id, kw);
keywords.add(kw);
//Abhängigkeitsbezeichnungen Ein Array von Abhängigkeitsinformationen
if (token.get("dependency_labels") != null) {
//Array abhängiger Informationen
JsonArray arrDependency = token.get("dependency_labels").getAsJsonArray();
for (int n = 0; n < arrDependency.size(); n++) {
//Abhängigkeitsinformationen
JsonObject objDependency = arrDependency.get(n).getAsJsonObject();
String dependency_token_id = "" + objDependency.get("token_id").getAsInt();
//Legen Sie Abhängigkeitsinformationen für Schlüsselwörter fest
kw.setDependencyKey(dependency_token_id);
}
}
} // END OF FOR EACH TOKENS
} // END OF FOR EACH (chunk_tokens)
// <Den Baum zusammenbauen>
// FOR EACH(chunk_tokens)
for (int idxChunkTokens = 0; idxChunkTokens < arrChunkTokens.size(); idxChunkTokens++) {
JsonObject chunk_token = arrChunkTokens.get(idxChunkTokens).getAsJsonObject();
// 2. tokens
JsonArray tokens = chunk_token.get("tokens").getAsJsonArray();
// FOR (EACH TOKEN)
for (int idxTokens = 0; idxTokens < tokens.size(); idxTokens++) {
JsonObject token = tokens.get(idxTokens).getAsJsonObject();
String id = "" + token.get("id").getAsInt();
DefaultKeywordWithDependency kw = mapIdKwd.get(id);
// dependency labels
if (token.get("dependency_labels") != null) {
JsonArray arr_dependency_labels = token.get("dependency_labels").getAsJsonArray();
for (int n = 0; n < arr_dependency_labels.size(); n++) {
JsonObject dependency_label = arr_dependency_labels.get(n).getAsJsonObject();
String childID = "" + dependency_label.get("token_id").getAsInt();
String labelDependency = dependency_label.get("label").getAsString();
//Überprüfen Sie, ob es Sätze überspannt
int sentence1 = idSentenceMap.get(token.get("id").getAsInt());
int sentence2 = idSentenceMap.get(dependency_label.get("token_id").getAsInt());
//Überspannen Sie keine Sätze
if (mapIdKwd.get(childID) != null && (sentence1 == sentence2)) {
//Eltern und Kind sind in Japanisch und Englisch vertauscht
DefaultKeywordWithDependency kw1Child = mapIdKwd.get(childID);
DefaultKeywordWithDependency kw2Parent = kw;
kw2Parent.addChild(kw1Child);
kw1Child.setRelation(labelDependency);
if (kw1Child.getBegin() < kw2Parent.getBegin()) {
DefaultKeyword kwd = new DefaultKeyword();
kwd.setBegin(kw1Child.getBegin());
kwd.setEnd(kw2Parent.getEnd());
kwd.setLex(kw1Child.getLex() + " ... " + kw2Parent.getLex());
kwd.setFacet(labelDependency);
patternKeywords.add(kwd);
} else {
DefaultKeyword kwd = new DefaultKeyword();
kwd.setBegin(kw2Parent.getBegin());
kwd.setEnd(kw1Child.getEnd());
kwd.setLex(kw2Parent.getLex() + " ... " + kw1Child.getLex());
kwd.setFacet(labelDependency);
patternKeywords.add(kwd);
}
} //
}
}
} // END OF FOR EACH TOKEN
} // END OF FOR EACH (chunk_tokens)
for (String link : chunkLinks) {
String id1 = link.split("/")[0];
String relation = link.split("/")[1];
String id2 = link.split("/")[2];
Keyword kwd1 = mapTokenidKwd.get(id1 + "-0");
Keyword kwd2 = mapTokenidKwd.get(id2 + "-0");
String lex1 = kwd1.getLex();
String lex2 = kwd2.getLex();
DefaultKeyword kwd = new DefaultKeyword();
kwd.setBegin(kwd1.getBegin());
kwd.setEnd(kwd2.getEnd());
kwd.setLex(lex2 + " ... " + lex1);
kwd.setStr(kwd.getLex());
kwd.setFacet(relation);
chunkLinkKeywords.add(kwd);
}
// </Den Baum zusammenbauen>
for (String key : mapIdKwd.keySet()) {
DefaultKeywordWithDependency kw = mapIdKwd.get(key);
// IF(Wenn es sich um ein Root-Schlüsselwort handelt)
if (kw.getParent() == null) {
roots.add(kw);
}
}
} // end of parse()
}
Wenn Sie in Bezug auf die Syntaxanalyse der COTOHA-API zwei Sätze wie "Es ist heute ein schöner Tag. Ich gehe morgen zur Schule." Analysieren, wird anscheinend eine Abhängigkeit zurückgegeben, die zwei Sätze umfasst. (Bitte weisen Sie darauf hin, wenn die Erkennung falsch ist)
Auf der Analyse-Demoseite werden zwei Sätze geteilt, aber dies scheint die Syntaxanalyse zu verarbeiten, nachdem die Sätze im Voraus durch Satzzeichen getrennt wurden.
Daher zählt dieser Parser die "Anzahl der Sätze" im Voraus wie folgt.
Ich versuche, die Abhängigkeit zwischen Sätzen zu ignorieren.
Als TestCase werde ich den JSON analysieren, der das Ergebnis der COTOHA-Syntaxanalyse-API gespeichert hat, und es als Zeichen ausgeben. (Geplant, zu einem späteren Zeitpunkt auf Github veröffentlicht zu werden)
File file = new File("src/test/resources/nlp_v1_parse_002.json");
String json = FileUtils.readFileToString(file, "UTF-8");
CotohaNlpV1ResponseHandler handler = new CotohaNlpV1ResponseHandler();
handler.parse(json);
for (DefaultKeywordWithDependency root : handler.getRoots()) {
System.err.println(root.toStringAsDependencyTree());
}
System.err.println("---");
for (Keyword kwd : handler.getKeywords()) {
System.err.println(kwd.getLex() + " (" + "word." + kwd.getFacet() + ")");
System.err.println("\t" + kwd);
}
System.err.println("---");
for (Keyword kwd : handler.getPatternKeywords()) {
System.err.println(kwd.getLex() + " (" + "pattern." + kwd.getFacet() + ")");
System.err.println("\t" + kwd);
}
System.err.println("---");
for (Keyword kwd : handler.getChunkLinkKeywords()) {
System.err.println(kwd.getLex() + " (" + "pattern." + kwd.getFacet() + ")");
System.err.println("\t" + kwd);
}
Es sieht wie folgt aus. Es ist schwer zu lesen, ob es sich um rohes JSON handelt, aber ich habe versucht, es in einer Baumform auszugeben. Der Zustand der Abhängigkeit ist leichter zu verstehen.
-sequence=11,lex=gehen,str=Linie,relation=null
-sequence=7,lex=Morgen,str=Morgen,relation=nmod
-sequence=8,lex=Ist,str=Ist,relation=case
-sequence=9,lex=Schule,str=Schule,relation=nmod
-sequence=10,lex=Zu,str=Zu,relation=case
-sequence=12,lex=Ki,str=Ki,relation=aux
-sequence=13,lex=Masu,str=Masu,relation=aux
-sequence=14,lex=。,str=。,relation=punct
-sequence=4,lex=Wetter,str=Wetter,relation=null
-sequence=0,lex=heute,str=heute,relation=nmod
-sequence=1,lex=Ist,str=Ist,relation=case
-sequence=2,lex=Gut,str=ich,relation=amod
-sequence=3,lex=ich,str=ich,relation=aux
-sequence=5,lex=ist,str=ist,relation=cop
-sequence=6,lex=。,str=。,relation=punct
---
heute(word.Substantiv)
heute[relation=nmod, sequence=0, dependencyKey=1, hasChildren=true, hasParent=false, facet=Substantiv, lex=heute, str=heute, reading=heute, begin=0, end=2]
Ist(word.Aufeinanderfolgende Hilfswörter)
Ist[relation=case, sequence=1, dependencyKey=null, hasChildren=false, hasParent=false, facet=Aufeinanderfolgende Hilfswörter, lex=Ist, str=Ist, reading=C., begin=2, end=3]
Gut(word.Adjektivstamm)
Gut[relation=amod, sequence=2, dependencyKey=3, hasChildren=true, hasParent=false, facet=Adjektivstamm, lex=Gut, str=ich, reading=ich, begin=3, end=4]
ich(word.Adjektivsuffix)
ich[relation=aux, sequence=3, dependencyKey=null, hasChildren=false, hasParent=false, facet=Adjektivsuffix, lex=ich, str=ich, reading=ich, begin=4, end=5]
Wetter(word.Substantiv)
Wetter[relation=null, sequence=4, dependencyKey=6, hasChildren=true, hasParent=true, facet=Substantiv, lex=Wetter, str=Wetter, reading=Wetter, begin=5, end=7]
ist(word.Beurteilung)
ist[relation=cop, sequence=5, dependencyKey=null, hasChildren=false, hasParent=false, facet=Beurteilung, lex=ist, str=ist, reading=Tod, begin=7, end=9]
。 (word.Phrase)
。 [relation=punct, sequence=6, dependencyKey=null, hasChildren=false, hasParent=false, facet=Phrase, lex=。, str=。, reading=, begin=9, end=10]
Morgen(word.Substantiv)
Morgen[relation=nmod, sequence=7, dependencyKey=8, hasChildren=true, hasParent=false, facet=Substantiv, lex=Morgen, str=Morgen, reading=Arsch, begin=10, end=12]
Ist(word.Aufeinanderfolgende Hilfswörter)
Ist[relation=case, sequence=8, dependencyKey=null, hasChildren=false, hasParent=false, facet=Aufeinanderfolgende Hilfswörter, lex=Ist, str=Ist, reading=C., begin=12, end=13]
Schule(word.Substantiv)
Schule[relation=nmod, sequence=9, dependencyKey=10, hasChildren=true, hasParent=false, facet=Substantiv, lex=Schule, str=Schule, reading=Gakkou, begin=13, end=15]
Zu(word.Fallassistent)
Zu[relation=case, sequence=10, dependencyKey=null, hasChildren=false, hasParent=false, facet=Fallassistent, lex=Zu, str=Zu, reading=D., begin=15, end=16]
gehen(word.Verbstamm)
gehen[relation=null, sequence=11, dependencyKey=14, hasChildren=true, hasParent=true, facet=Verbstamm, lex=gehen, str=Linie, reading=ich, begin=16, end=17]
Ki(word.Verbale Nutzung endet)
Ki[relation=aux, sequence=12, dependencyKey=null, hasChildren=false, hasParent=false, facet=Verbale Nutzung endet, lex=Ki, str=Ki, reading=Ki, begin=17, end=18]
Masu(word.Verbsuffix)
Masu[relation=aux, sequence=13, dependencyKey=null, hasChildren=false, hasParent=false, facet=Verbsuffix, lex=Masu, str=Masu, reading=Forelle, begin=18, end=20]
。 (word.Phrase)
。 [relation=punct, sequence=14, dependencyKey=null, hasChildren=false, hasParent=false, facet=Phrase, lex=。, str=。, reading=, begin=20, end=21]
---
heute...Ist(pattern.case)
heute...Ist[sequence=-1, facet=case, lex=heute...Ist, str=null, reading=null, count=-1, begin=0, end=3, correlation=0.0]
Gut...ich(pattern.aux)
Gut...ich[sequence=-1, facet=aux, lex=Gut...ich, str=null, reading=null, count=-1, begin=3, end=5, correlation=0.0]
heute...Wetter(pattern.nmod)
heute...Wetter[sequence=-1, facet=nmod, lex=heute...Wetter, str=null, reading=null, count=-1, begin=0, end=7, correlation=0.0]
Gut...Wetter(pattern.amod)
Gut...Wetter[sequence=-1, facet=amod, lex=Gut...Wetter, str=null, reading=null, count=-1, begin=3, end=7, correlation=0.0]
Wetter...ist(pattern.cop)
Wetter...ist[sequence=-1, facet=cop, lex=Wetter...ist, str=null, reading=null, count=-1, begin=5, end=9, correlation=0.0]
Wetter... 。 (pattern.punct)
Wetter... 。 [sequence=-1, facet=punct, lex=Wetter... 。, str=null, reading=null, count=-1, begin=5, end=10, correlation=0.0]
Morgen...Ist(pattern.case)
Morgen...Ist[sequence=-1, facet=case, lex=Morgen...Ist, str=null, reading=null, count=-1, begin=10, end=13, correlation=0.0]
Schule...Zu(pattern.case)
Schule...Zu[sequence=-1, facet=case, lex=Schule...Zu, str=null, reading=null, count=-1, begin=13, end=16, correlation=0.0]
Morgen...gehen(pattern.nmod)
Morgen...gehen[sequence=-1, facet=nmod, lex=Morgen...gehen, str=null, reading=null, count=-1, begin=10, end=17, correlation=0.0]
Schule...gehen(pattern.nmod)
Schule...gehen[sequence=-1, facet=nmod, lex=Schule...gehen, str=null, reading=null, count=-1, begin=13, end=17, correlation=0.0]
gehen...Ki(pattern.aux)
gehen...Ki[sequence=-1, facet=aux, lex=gehen...Ki, str=null, reading=null, count=-1, begin=16, end=18, correlation=0.0]
gehen...Masu(pattern.aux)
gehen...Masu[sequence=-1, facet=aux, lex=gehen...Masu, str=null, reading=null, count=-1, begin=16, end=20, correlation=0.0]
gehen... 。 (pattern.punct)
gehen... 。 [sequence=-1, facet=punct, lex=gehen... 。, str=null, reading=null, count=-1, begin=16, end=21, correlation=0.0]
---
heute...Wetter(pattern.time)
heute...Wetter[sequence=-1, facet=time, lex=heute...Wetter, str=heute...Wetter, reading=null, count=-1, begin=5, end=2, correlation=0.0]
Gut...Wetter(pattern.adjectivals)
Gut...Wetter[sequence=-1, facet=adjectivals, lex=Gut...Wetter, str=Gut...Wetter, reading=null, count=-1, begin=5, end=4, correlation=0.0]
Wetter...gehen(pattern.manner)
Wetter...gehen[sequence=-1, facet=manner, lex=Wetter...gehen, str=Wetter...gehen, reading=null, count=-1, begin=16, end=7, correlation=0.0]
Morgen...gehen(pattern.time)
Morgen...gehen[sequence=-1, facet=time, lex=Morgen...gehen, str=Morgen...gehen, reading=null, count=-1, begin=16, end=12, correlation=0.0]
Schule...gehen(pattern.goal)
Schule...gehen[sequence=-1, facet=goal, lex=Schule...gehen, str=Schule...gehen, reading=null, count=-1, begin=16, end=15, correlation=0.0]
Die einfache Handhabung als Java-Klasse bedeutet, dass sie auch für den geschäftlichen Gebrauch einfach zu handhaben ist. Das Ergebnis der syntaktischen Analyse zu analysieren ist ein Problem, aber in der Geschäftswelt ist ** hier das Spiel **.
Recommended Posts