LUIS is called again with no context revoke.
This commit is contained in:
		
							parent
							
								
									d2a4855702
								
							
						
					
					
						commit
						4cc4e7236a
					
				
					 4 changed files with 153 additions and 135 deletions
				
			
		| 
						 | 
					@ -56,21 +56,11 @@ export class WelcomeDialog extends IGBDialog {
 | 
				
			||||||
            date < 12 ? "bom dia" : date < 18 ? "boa tarde" : "boa noite";
 | 
					            date < 12 ? "bom dia" : date < 18 ? "boa tarde" : "boa noite";
 | 
				
			||||||
          
 | 
					          
 | 
				
			||||||
          let messages = [`Oi, ${msg}.`, `Oi!`, `Olá, ${msg}`, `Olá!`];
 | 
					          let messages = [`Oi, ${msg}.`, `Oi!`, `Olá, ${msg}`, `Olá!`];
 | 
				
			||||||
          dc.end(messages);
 | 
					          
 | 
				
			||||||
 | 
					          if (dc.context.activity && dc.context.activity.text != "") {
 | 
				
			||||||
 | 
					            await dc.replace("/answer", { query: dc.context.activity.text });
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // V4: if (dc.context.message && dc.message.text != "") {
 | 
					 | 
				
			||||||
        //   dc.replace("/answer", { query: dc.message.text });
 | 
					 | 
				
			||||||
        //   return;
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
        // let userName = dc.message.user.name;
 | 
					 | 
				
			||||||
        // let displayName = dc.message.user.name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // if (args) {
 | 
					 | 
				
			||||||
        //   userName = args.userName;
 | 
					 | 
				
			||||||
        //   displayName = args.displayName;
 | 
					 | 
				
			||||||
        // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ import { GBError } from "botlib";
 | 
				
			||||||
import { GBERROR_TYPE } from "botlib";
 | 
					import { GBERROR_TYPE } from "botlib";
 | 
				
			||||||
import { GBMinInstance } from "botlib";
 | 
					import { GBMinInstance } from "botlib";
 | 
				
			||||||
import { LuisRecognizer } from "botbuilder-ai";
 | 
					import { LuisRecognizer } from "botbuilder-ai";
 | 
				
			||||||
 | 
					import {MessageFactory} from "botbuilder";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class GBConversationalService implements IGBConversationalService {
 | 
					export class GBConversationalService implements IGBConversationalService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,11 +54,11 @@ export class GBConversationalService implements IGBConversationalService {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sendEvent(dc: any, name: string, value: any) {
 | 
					    sendEvent(dc: any, name: string, value: any) {
 | 
				
			||||||
        var msg = new gBuilder.Message();
 | 
					        const msg = MessageFactory.text('');
 | 
				
			||||||
        msg.data.type = "event";
 | 
					        msg.value = value;
 | 
				
			||||||
        msg.data.name = name;
 | 
					        msg.type = "event";
 | 
				
			||||||
        msg.data.value = value;
 | 
					        msg.name = name;
 | 
				
			||||||
        dc.context.sendActivity(msg);
 | 
					        // TODO: dc.context.sendActivity(msg);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async runNLP(
 | 
					    async runNLP(
 | 
				
			||||||
| 
						 | 
					@ -73,7 +74,7 @@ export class GBConversationalService implements IGBConversationalService {
 | 
				
			||||||
            serviceEndpoint: min.instance.nlpServerUrl
 | 
					            serviceEndpoint: min.instance.nlpServerUrl
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await model.recognize(dc).then(res => {
 | 
					        await model.recognize(dc.context).then(res => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Resolve intents returned from LUIS
 | 
					            // Resolve intents returned from LUIS
 | 
				
			||||||
            let topIntent = LuisRecognizer.topIntent(res);
 | 
					            let topIntent = LuisRecognizer.topIntent(res);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,32 +223,26 @@ export class GBMinService {
 | 
				
			||||||
        logger.trace(
 | 
					        logger.trace(
 | 
				
			||||||
          `GeneralBots(${instance.engineName}) listening on: ${url}.`
 | 
					          `GeneralBots(${instance.engineName}) listening on: ${url}.`
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        server.post('/api/messages/', (req, res) => {
 | 
					        server.post(`/api/messages/${instance.botId}`, (req, res) => {
 | 
				
			||||||
          
 | 
					
 | 
				
			||||||
          adapter.processActivity(req, res, async (context) => {
 | 
					          adapter.processActivity(req, res, async (context) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (context.activity.type === 'message') {
 | 
					            const state = conversationState.get(context);
 | 
				
			||||||
              // Create dialog context and continue executing the "current" dialog, if any.
 | 
					            const dc = min.dialogs.createContext(context, state);
 | 
				
			||||||
              const state = conversationState.get(context);
 | 
					
 | 
				
			||||||
              const dc = min.dialogs.createContext(context, state);
 | 
					            if (context.activity.type === "conversationUpdate" &&
 | 
				
			||||||
 | 
					              context.activity.membersAdded.length > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              // TODO: Something when starting conversation here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              await dc.continue();
 | 
					              await dc.continue();
 | 
				
			||||||
 | 
					            } else if (context.activity.type === 'message') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              // Check to see if anyone replied. If not then start echo dialog
 | 
					              // Check to see if anyone replied. If not then start echo dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              if (!context.responded) {
 | 
					              if (!context.responded) {
 | 
				
			||||||
                await dc.begin('echo');
 | 
					                await dc.begin('/');
 | 
				
			||||||
              }
 | 
					              }else if (context.activity.name === "whoAmI") {
 | 
				
			||||||
 | 
					 | 
				
			||||||
              //   context.activity.type === "conversationUpdate" &&
 | 
					 | 
				
			||||||
              //   context.activity.membersAdded.length > 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              //   // if (context.activity.address.channelId != "directline") {
 | 
					 | 
				
			||||||
              //   //   dc.begin("/");
 | 
					 | 
				
			||||||
              //   // }
 | 
					 | 
				
			||||||
              //   // else {
 | 
					 | 
				
			||||||
              //   //   next();
 | 
					 | 
				
			||||||
              //   // }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
              if (context.activity.name === "whoAmI") {
 | 
					 | 
				
			||||||
                dc.begin("/whoAmI");
 | 
					                dc.begin("/whoAmI");
 | 
				
			||||||
              } else if (context.activity.name === "showSubjects") {
 | 
					              } else if (context.activity.name === "showSubjects") {
 | 
				
			||||||
                dc.begin("/menu");
 | 
					                dc.begin("/menu");
 | 
				
			||||||
| 
						 | 
					@ -273,16 +267,12 @@ export class GBMinService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              const user = min.userState.get(dc.context);
 | 
					              const user = min.userState.get(dc.context);
 | 
				
			||||||
              if (!user.loaded) {
 | 
					              if (!user.loaded) {
 | 
				
			||||||
                setTimeout(
 | 
					                // min.conversationalService.sendEvent(
 | 
				
			||||||
                  () => {
 | 
					                //   dc,
 | 
				
			||||||
                    min.conversationalService.sendEvent(
 | 
					                //   "loadInstance",
 | 
				
			||||||
                      dc,
 | 
					                //   min.instance // TODO: Send a new thiner object.
 | 
				
			||||||
                      "loadInstance",
 | 
					                // );
 | 
				
			||||||
                      min.instance // TODO: Send a new thiner object.
 | 
					
 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                  500
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                user.loaded = true;
 | 
					                user.loaded = true;
 | 
				
			||||||
                user.subjects = [];
 | 
					                user.subjects = [];
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,7 @@ import { AzureText } from "pragmatismo-io-framework";
 | 
				
			||||||
import { GBMinInstance } from "botlib";
 | 
					import { GBMinInstance } from "botlib";
 | 
				
			||||||
import { KBService } from './../services/KBService';
 | 
					import { KBService } from './../services/KBService';
 | 
				
			||||||
import { BotAdapter } from "botbuilder";
 | 
					import { BotAdapter } from "botbuilder";
 | 
				
			||||||
 | 
					import { LuisRecognizer } from "botbuilder-ai";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const logger = require("../../../src/logger");
 | 
					const logger = require("../../../src/logger");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +46,13 @@ export class AskDialog extends IGBDialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const service = new KBService();
 | 
					    const service = new KBService();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const model = new LuisRecognizer({
 | 
				
			||||||
 | 
					      appId: min.instance.nlpAppId,
 | 
				
			||||||
 | 
					      subscriptionKey: min.instance.nlpSubscriptionKey,
 | 
				
			||||||
 | 
					      serviceEndpoint: min.instance.nlpServerUrl
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    min.dialogs.add("/answer", [
 | 
					    min.dialogs.add("/answer", [
 | 
				
			||||||
      async (dc, args) => {
 | 
					      async (dc, args) => {
 | 
				
			||||||
        const user = min.userState.get(dc.context);
 | 
					        const user = min.userState.get(dc.context);
 | 
				
			||||||
| 
						 | 
					@ -63,102 +71,128 @@ export class AskDialog extends IGBDialog {
 | 
				
			||||||
          dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
					          dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (text === "") {
 | 
					      await model.recognize(dc.context).then(res => {
 | 
				
			||||||
          dc.replace("/ask");
 | 
					        console.log(res);
 | 
				
			||||||
        } else {
 | 
					      }).catch(err => {
 | 
				
			||||||
          AzureText.getSpelledText(
 | 
					        console.log(err);
 | 
				
			||||||
            min.instance.spellcheckerKey,
 | 
					      });
 | 
				
			||||||
            text,
 | 
					 | 
				
			||||||
            (data, err) => {
 | 
					 | 
				
			||||||
              if (data != text) {
 | 
					 | 
				
			||||||
                logger.trace("Spelled Text: " + data);
 | 
					 | 
				
			||||||
                text = data;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              user.lastQuestion = data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
              service.ask(
 | 
					        // await min.conversationalService.runNLP(
 | 
				
			||||||
                min.instance,
 | 
					        //   dc,
 | 
				
			||||||
                text,
 | 
					        //   min,
 | 
				
			||||||
                min.instance.searchScore,
 | 
					        //   text,
 | 
				
			||||||
                user.subjects,
 | 
					        //   (data, error) => {
 | 
				
			||||||
                resultsA => {
 | 
					 | 
				
			||||||
                  min.conversationalService.sendEvent(dc, "stop", null);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  if (resultsA && resultsA.answer) {
 | 
					        //     if (!data) {
 | 
				
			||||||
                    user.isAsking = false;
 | 
					        //       let messages = [
 | 
				
			||||||
                    service.sendAnswer(min.conversationalService,
 | 
					        //         "Desculpe-me, não encontrei nada a respeito.",
 | 
				
			||||||
                      dc,
 | 
					        //         "Lamento... Não encontrei nada sobre isso. Vamos tentar novamente?",
 | 
				
			||||||
                      resultsA.answer
 | 
					        //         "Desculpe-me, não achei nada parecido. Poderia tentar escrever de outra forma?"
 | 
				
			||||||
                    );
 | 
					        //       ];
 | 
				
			||||||
                    user.lastQuestionId = resultsA.questionId;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    dc.replace("/ask", { isReturning: true });
 | 
					        //       dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
				
			||||||
                  } else {
 | 
					        //       dc.replace("/ask", { isReturning: true });
 | 
				
			||||||
                    //if (min.isAsking) {
 | 
					        //     }
 | 
				
			||||||
                    // Second time with no filter.
 | 
					        //   }
 | 
				
			||||||
 | 
					        // );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    service.ask(
 | 
					 | 
				
			||||||
                      min.instance,
 | 
					 | 
				
			||||||
                      text,
 | 
					 | 
				
			||||||
                      min.instance.searchScore,
 | 
					 | 
				
			||||||
                      null,
 | 
					 | 
				
			||||||
                      resultsB => {
 | 
					 | 
				
			||||||
                        if (resultsB && resultsB.answer) {
 | 
					 | 
				
			||||||
                          const user = min.userState.get(dc.context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                          user.isAsking = false;
 | 
					        // if (text === "") {
 | 
				
			||||||
 | 
					        //   dc.replace("/ask");
 | 
				
			||||||
 | 
					        // } else {
 | 
				
			||||||
 | 
					        //   // AzureText.getSpelledText(
 | 
				
			||||||
 | 
					        //   //   min.instance.spellcheckerKey,
 | 
				
			||||||
 | 
					        //   //   text,
 | 
				
			||||||
 | 
					        //   //   async (data, err) => {
 | 
				
			||||||
 | 
					        //   var data = text;
 | 
				
			||||||
 | 
					        //   if (data != text) {
 | 
				
			||||||
 | 
					        //     logger.trace("Spelled Text: " + data);
 | 
				
			||||||
 | 
					        //     text = data;
 | 
				
			||||||
 | 
					        //   }
 | 
				
			||||||
 | 
					        //   user.lastQuestion = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                          if (user.subjects.length > 0) {
 | 
					        //   service.ask(
 | 
				
			||||||
                            let subjectText =
 | 
					        //     min.instance,
 | 
				
			||||||
                              `${KBService.getSubjectItemsSeparatedBySpaces(
 | 
					        //     text,
 | 
				
			||||||
                                user.subjects
 | 
					        //     min.instance.searchScore,
 | 
				
			||||||
                              )}`;
 | 
					        //     user.subjects,
 | 
				
			||||||
 | 
					        //     async resultsA => {
 | 
				
			||||||
 | 
					        //       min.conversationalService.sendEvent(dc, "stop", null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            let messages = [
 | 
					        //       if (resultsA && resultsA.answer) {
 | 
				
			||||||
                              `Respondendo nao apenas sobre ${subjectText}... `,
 | 
					        //         user.isAsking = false;
 | 
				
			||||||
                              `Respondendo de modo mais abrangente...`,
 | 
					        //         service.sendAnswer(min.conversationalService,
 | 
				
			||||||
                              `Vou te responder de modo mais abrangente... 
 | 
					        //           dc,
 | 
				
			||||||
                                Não apenas sobre ${subjectText}`
 | 
					        //           resultsA.answer
 | 
				
			||||||
                            ];
 | 
					        //         );
 | 
				
			||||||
                            dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
					        //         user.lastQuestionId = resultsA.questionId;
 | 
				
			||||||
                          }
 | 
					 | 
				
			||||||
                          user.isAsking = false;
 | 
					 | 
				
			||||||
                          service.sendAnswer(min.conversationalService,
 | 
					 | 
				
			||||||
                            dc,
 | 
					 | 
				
			||||||
                            resultsB.answer
 | 
					 | 
				
			||||||
                          );
 | 
					 | 
				
			||||||
                          dc.replace("/ask", { isReturning: true });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                          user.lastQuestionId = resultsB.questionId;
 | 
					        //         dc.replace("/ask", { isReturning: true });
 | 
				
			||||||
                        } else {
 | 
					        //       } else {
 | 
				
			||||||
 | 
					        //         //if (min.isAsking) {
 | 
				
			||||||
 | 
					        //         // Second time with no filter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                          min.conversationalService.runNLP(
 | 
					        //         service.ask(
 | 
				
			||||||
                            dc,
 | 
					        //           min.instance,
 | 
				
			||||||
                            min,
 | 
					        //           text,
 | 
				
			||||||
                            text,
 | 
					        //           min.instance.searchScore,
 | 
				
			||||||
                            (data, error) => {
 | 
					        //           null,
 | 
				
			||||||
 | 
					        //           async resultsB => {
 | 
				
			||||||
 | 
					        //             if (resultsB && resultsB.answer) {
 | 
				
			||||||
 | 
					        //               const user = min.userState.get(dc.context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                              if (!data) {
 | 
					        //               user.isAsking = false;
 | 
				
			||||||
                                let messages = [
 | 
					 | 
				
			||||||
                                  "Desculpe-me, não encontrei nada a respeito.",
 | 
					 | 
				
			||||||
                                  "Lamento... Não encontrei nada sobre isso. Vamos tentar novamente?",
 | 
					 | 
				
			||||||
                                  "Desculpe-me, não achei nada parecido. Poderia tentar escrever de outra forma?"
 | 
					 | 
				
			||||||
                                ];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
					        //               if (user.subjects.length > 0) {
 | 
				
			||||||
                                dc.replace("/ask", { isReturning: true });
 | 
					        //                 let subjectText =
 | 
				
			||||||
                              }
 | 
					        //                   `${KBService.getSubjectItemsSeparatedBySpaces(
 | 
				
			||||||
                            }
 | 
					        //                     user.subjects
 | 
				
			||||||
                          );
 | 
					        //                   )}`;
 | 
				
			||||||
                        }
 | 
					
 | 
				
			||||||
                      }
 | 
					        //                 let messages = [
 | 
				
			||||||
                    );
 | 
					        //                   `Respondendo nao apenas sobre ${subjectText}... `,
 | 
				
			||||||
                  }
 | 
					        //                   `Respondendo de modo mais abrangente...`,
 | 
				
			||||||
                }
 | 
					        //                   `Vou te responder de modo mais abrangente... 
 | 
				
			||||||
              );
 | 
					        //                         Não apenas sobre ${subjectText}`
 | 
				
			||||||
            }
 | 
					        //                 ];
 | 
				
			||||||
          );
 | 
					        //                 dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
				
			||||||
        }
 | 
					        //               }
 | 
				
			||||||
 | 
					        //               user.isAsking = false;
 | 
				
			||||||
 | 
					        //               service.sendAnswer(min.conversationalService,
 | 
				
			||||||
 | 
					        //                 dc,
 | 
				
			||||||
 | 
					        //                 resultsB.answer
 | 
				
			||||||
 | 
					        //               );
 | 
				
			||||||
 | 
					        //               dc.replace("/ask", { isReturning: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //               user.lastQuestionId = resultsB.questionId;
 | 
				
			||||||
 | 
					        //             } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //               await min.conversationalService.runNLP(
 | 
				
			||||||
 | 
					        //                 dc,
 | 
				
			||||||
 | 
					        //                 min,
 | 
				
			||||||
 | 
					        //                 text,
 | 
				
			||||||
 | 
					        //                 (data, error) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //                   if (!data) {
 | 
				
			||||||
 | 
					        //                     let messages = [
 | 
				
			||||||
 | 
					        //                       "Desculpe-me, não encontrei nada a respeito.",
 | 
				
			||||||
 | 
					        //                       "Lamento... Não encontrei nada sobre isso. Vamos tentar novamente?",
 | 
				
			||||||
 | 
					        //                       "Desculpe-me, não achei nada parecido. Poderia tentar escrever de outra forma?"
 | 
				
			||||||
 | 
					        //                     ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //                     dc.context.sendActivity(messages[0]); // TODO: Handle rnd.
 | 
				
			||||||
 | 
					        //                     dc.replace("/ask", { isReturning: true });
 | 
				
			||||||
 | 
					        //                   }
 | 
				
			||||||
 | 
					        //                 }
 | 
				
			||||||
 | 
					        //               );
 | 
				
			||||||
 | 
					        //             }
 | 
				
			||||||
 | 
					        //           }
 | 
				
			||||||
 | 
					        //         );
 | 
				
			||||||
 | 
					        //       }
 | 
				
			||||||
 | 
					        //     }
 | 
				
			||||||
 | 
					        //   );
 | 
				
			||||||
 | 
					        // }
 | 
				
			||||||
 | 
					        //);        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,6 +201,9 @@ export class AskDialog extends IGBDialog {
 | 
				
			||||||
      async (dc, args) => {
 | 
					      async (dc, args) => {
 | 
				
			||||||
        const user = min.userState.get(dc.context);
 | 
					        const user = min.userState.get(dc.context);
 | 
				
			||||||
        user.isAsking = true;
 | 
					        user.isAsking = true;
 | 
				
			||||||
 | 
					        if (!user.subjects) {
 | 
				
			||||||
 | 
					          user.subjects = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        let text = [];
 | 
					        let text = [];
 | 
				
			||||||
        if (user.subjects.length > 0) {
 | 
					        if (user.subjects.length > 0) {
 | 
				
			||||||
          text = [
 | 
					          text = [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue