agora-edu-core
Version:
Core APIs for building an online classroom
648 lines (630 loc) • 25.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MessagesStore = void 0;
require("core-js/modules/esnext.map.delete-all.js");
require("core-js/modules/esnext.map.every.js");
require("core-js/modules/esnext.map.filter.js");
require("core-js/modules/esnext.map.find.js");
require("core-js/modules/esnext.map.find-key.js");
require("core-js/modules/esnext.map.includes.js");
require("core-js/modules/esnext.map.key-of.js");
require("core-js/modules/esnext.map.map-keys.js");
require("core-js/modules/esnext.map.map-values.js");
require("core-js/modules/esnext.map.merge.js");
require("core-js/modules/esnext.map.reduce.js");
require("core-js/modules/esnext.map.some.js");
require("core-js/modules/esnext.map.update.js");
var _agoraRteSdk = require("agora-rte-sdk");
var _get = _interopRequireDefault(require("lodash/get"));
var _mobx = require("mobx");
var _configs = require("../../../../configs");
var _type = require("../../../../type");
var _utils = require("../../../../utils");
var _error = require("../../../../utils/error");
var _base = require("../base");
var _struct = require("./struct");
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec0, _class, _descriptor, _dec1, _dec10, _dec11, _dec12, _dec13, _dec14, _class2, _descriptor2, _SceneEventHandler;
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _initializerDefineProperty(e, i, r, l) { r && Object.defineProperty(e, i, { enumerable: r.enumerable, configurable: r.configurable, writable: r.writable, value: r.initializer ? r.initializer.call(l) : void 0 }); }
function _applyDecoratedDescriptor(i, e, r, n, l) { var a = {}; return Object.keys(n).forEach(function (i) { a[i] = n[i]; }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) { return n(i, e, r) || r; }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a; }
function _initializerWarningHelper(r, e) { throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform."); }
/**
* `MessagesStore` 类用于处理各种聊天消息及IM信令控制。
*/
/** @en
* The `MessagesStore` class is used for dealing with hat messages and various kinds of chat signal that controls the IM state.
*/
let MessagesStore = exports.MessagesStore = (_dec = _mobx.action.bound, _dec2 = _mobx.action.bound, _dec3 = _mobx.action.bound, _dec4 = _mobx.action.bound, _dec5 = _mobx.action.bound, _dec6 = _mobx.action.bound, _dec7 = _mobx.action.bound, _dec8 = _mobx.action.bound, _dec9 = _mobx.action.bound, _dec0 = _mobx.action.bound, _class = class MessagesStore extends _base.EduStoreBase {
constructor(...args) {
super(...args);
this._disposers = [];
_initializerDefineProperty(this, "_dataStore", _descriptor, this);
}
/**
* 是否禁止聊天
*/
/** @en
* Whether the chat is muted or not
*/
get chatMuted() {
return this._dataStore.chatMuted;
}
/**
* 历史消息列表
*/
/** @en
* Chat history message list
*/
get roomChatMessages() {
return this._dataStore.roomChatMessages;
}
/**
* 会话列表
*/
/** @en
* Conversation list
*/
get roomChatConversations() {
return this._dataStore.roomChatConversations;
}
/**
* 未读消息数量
*/
/** @en
* Number of unread message count
*/
get unreadMessageCount() {
return this._dataStore.unreadMessageCount;
}
/**
*
*/
/** @en
*
*/
get chatConvasationUserUuid() {
return this._dataStore.chatConvasationUserUuid;
}
/**
*
*/
get chatConvasationMessageId() {
return this._dataStore.chatConvasationMessageId;
}
/**
*
*/
get roomChatMessagesMessageId() {
return this._dataStore.roomChatMessagesMessageId;
}
/**
*
*/
get newMessageFlag() {
return this._dataStore.newMessageFlag;
}
/**
* 增加一条消息到消息列表
* @param args
*/
/** @en
* Adds a message to the message list
* @param args
*/
addChatMessage(args) {
this.roomChatMessages.push(args);
this.roomChatMessagesMessageId.set(args.messageId, args);
}
/**
*
* @param conversation
*/
/**
*
* @param conversation
*/
addRoomChatConversation(conversation) {
this.roomChatConversations.push(conversation);
this.chatConvasationUserUuid.set(conversation.userUuid, conversation);
conversation.messages.forEach(message => {
this.chatConvasationMessageId.set(message.messageId, message);
});
}
/**
*
* @param args
* @param conversation
*/
/** @en
*
* @param args
* @param conversation
*/
addConversationChatMessage(args, conversation) {
const chatConversation = this.chatConvasationUserUuid.get(conversation.userUuid);
if (!chatConversation) {
this.addRoomChatConversation(conversation);
} else {
!this.chatConvasationMessageId.has(args.messageId) && chatConversation.messages.push(args);
}
}
/**
* 获取房间历史的聊天消息
* @param data
* @returns
*/
/** @en
* 获取房间历史的聊天消息
* @param data
* @returns
*/
async getHistoryChatMessage(data) {
try {
const {
userUuid: currentUserUuid
} = _configs.EduClassroomConfig.shared.sessionInfo;
const historyMessage = await this.classroomStore.api.getHistoryChatMessage({
roomUuid: this.classroomStore.connectionStore.sceneId,
userUuid: currentUserUuid,
data
});
(0, _mobx.runInAction)(() => {
historyMessage.list.forEach(item => {
var _item$ext;
let {
fromUser: {
userUuid,
userName
}
} = item;
const {
fromUser: {
role
},
message,
sendTime,
messageId
} = item;
const isBroadcast = ((_item$ext = item.ext) === null || _item$ext === void 0 ? void 0 : _item$ext.range) === 3;
if (isBroadcast) {
userUuid = item.ext.userUuid;
userName = item.ext.userName;
}
const formatedItem = new _struct.MessageItem({
content: message,
ts: sendTime,
id: userUuid,
userName,
role: role,
messageId: messageId,
isOwn: userUuid === userUuid,
isBroadcast
});
if (!this.roomChatMessagesMessageId.has(formatedItem.messageId)) {
this.roomChatMessages.unshift(formatedItem);
this.roomChatMessagesMessageId.set(formatedItem.messageId, formatedItem);
}
});
});
return historyMessage;
} catch (e) {
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_GET_HISTORY_CHAT_MESSAGE_FAIL, e);
}
}
/**
* 根据学生 ID 获取学生的提问消息
* @param data
*/
/** @en
* 根据学生 ID 获取学生的提问消息
* @param data
*/
async getConversationHistoryChatMessage(data) {
try {
const historyMessage = await this.classroomStore.api.getConversationHistoryChatMessage({
roomUuid: this.classroomStore.connectionStore.sceneId,
data
});
let conversation = this.chatConvasationUserUuid.get(data.studentUuid);
if (!conversation) {
const messages = [];
for (const message of historyMessage.list) {
const conversationMessage = new _struct.MessageItem({
content: message.message,
ts: message.sendTime,
id: message.fromUser.userUuid,
userName: message.fromUser.userName,
role: message.fromUser.role,
messageId: message.peerMessageId,
isOwn: message.fromUser.userUuid === _configs.EduClassroomConfig.shared.sessionInfo.userUuid,
isBroadcast: false
});
messages.unshift(conversationMessage);
}
conversation = new _struct.Conversation({
userUuid: data.studentUuid,
userName: '',
unreadMessageCount: 0,
messages
});
(0, _mobx.runInAction)(() => {
this.addRoomChatConversation(conversation);
});
} else {
(0, _mobx.runInAction)(() => {
for (const message of historyMessage.list) {
if (!this.chatConvasationMessageId.has(message.peerMessageId)) {
const conversationMessage = new _struct.MessageItem({
content: message.message,
ts: message.sendTime,
id: message.fromUser.userUuid,
userName: message.fromUser.userName,
role: message.fromUser.role,
messageId: message.peerMessageId,
isOwn: message.fromUser.userUuid === _configs.EduClassroomConfig.shared.sessionInfo.userUuid,
isBroadcast: false
});
conversation.messages.unshift(conversationMessage);
this.chatConvasationMessageId.set(message.peerMessageId, conversationMessage);
}
}
});
}
} catch (e) {
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_GET_COVERSATION_HISTORY_CHAT_MESSAGE_FAIL, e);
}
}
/**
* 获取 提问列表用户信息
* @param data
*/
/** @en
* 获取 提问列表用户信息
* @param data
*/
async getConversationList(data) {
try {
const conversation = await this.classroomStore.api.getConversationList({
roomUuid: this.classroomStore.connectionStore.sceneId,
data
});
(0, _mobx.runInAction)(() => {
conversation.list.forEach(item => {
const formatedItem = new _struct.Conversation({
userName: item.userName,
userUuid: item.userUuid,
unreadMessageCount: 0,
messages: [],
timestamp: item.lastMessageTs
});
this.addRoomChatConversation(formatedItem);
});
});
return conversation;
} catch (e) {
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_GET_CONVERSATION_LIST_FAIL, e);
}
}
/**
* 禁止聊天
*/
/** @en
* Mutes chat
*/
async muteChat() {
try {
await this.classroomStore.api.muteChat({
roomUuid: this.classroomStore.connectionStore.sceneId,
muteChat: 1
});
} catch (e) {
// throw an error
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_MUTE_CHAT_FAIL, e);
}
}
/**
* 解除禁止聊天
*/
/** @en
* Unmutes chat
*/
async unmuteChat() {
try {
await this.classroomStore.api.muteChat({
roomUuid: this.classroomStore.connectionStore.sceneId,
muteChat: 0
});
} catch (e) {
// throw an error
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_UN_MUTE_CHAT_FAIL, e);
}
}
/**
* 重置未读消息数
*/
/** @en
* Resets unread messages count
*/
resetUnreadMessageCount() {
this._dataStore.unreadMessageCount = 0;
}
/**
* 增加未读消息总数
*/
/** @en
* Increment unread messages count
*/
incrementUnreadMessageCount() {
this._dataStore.unreadMessageCount++;
}
/**
* 发送消息
* @param message
*/
/** @en
* Sends a message
* @param message
*/
async sendMessage(message) {
try {
const {
userUuid
} = _configs.EduClassroomConfig.shared.sessionInfo;
const ts = +Date.now();
await this.classroomStore.api.sendChat({
roomUuid: this.classroomStore.connectionStore.sceneId,
userUuid: userUuid,
data: {
message,
type: 1
}
});
} catch (e) {
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_SEND_MESSAGE_FAIL, e);
}
}
/**
* 发送会话消息
* @param message
* @param conversation
*/
/** @en
* Sends message to a conversation
* @param message
* @param conversation
*/
async sendMessageToConversation(message, conversation) {
try {
const {
userUuid: currentUserUuid,
userName
} = _configs.EduClassroomConfig.shared.sessionInfo;
const ts = +Date.now();
const result = await this.classroomStore.api.sendConversationChat({
roomUuid: this.classroomStore.connectionStore.sceneId,
userUuid: conversation.userUuid,
data: {
message,
type: 1
}
});
const conversationMessage = new _struct.MessageItem({
id: currentUserUuid,
userName,
ts,
content: result.message,
isOwn: true,
messageId: result.peerMessageId,
role: result.role,
isBroadcast: false
});
conversation.messages = [conversationMessage];
this.addConversationChatMessage(conversationMessage, conversation);
} catch (e) {
_error.EduErrorCenter.shared.handleThrowableError(_error.AGEduErrorCode.EDU_ERR_SEND_MESSAGE_CONVERSATION_FAIL, e);
}
}
_setEventHandler(scene) {
if (this.classroomStore.connectionStore.mainRoomScene === scene) {
let handler = SceneEventHandler.getEventHandler(scene);
if (!handler) {
handler = SceneEventHandler.createEventHandler(scene);
}
this._dataStore = handler.dataStore;
} else {
const handler = SceneEventHandler.createEventHandler(scene);
this._dataStore = handler.dataStore;
}
}
onInstall() {
this._disposers.push((0, _mobx.computed)(() => this.classroomStore.connectionStore.scene).observe(({
newValue,
oldValue
}) => {
if (newValue) {
this._setEventHandler(newValue);
}
}));
}
onDestroy() {
SceneEventHandler.cleanup();
this._disposers.forEach(d => d());
this._disposers = [];
}
}, _descriptor = _applyDecoratedDescriptor(_class.prototype, "_dataStore", [_mobx.observable], {
configurable: true,
enumerable: true,
writable: true,
initializer: function () {
return {
roomChatMessages: [],
roomChatConversations: [],
unreadMessageCount: 0,
chatConvasationUserUuid: new Map(),
chatConvasationMessageId: new Map(),
roomChatMessagesMessageId: new Map(),
newMessageFlag: false,
chatMuted: false
};
}
}), _applyDecoratedDescriptor(_class.prototype, "chatMuted", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "chatMuted"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "roomChatMessages", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "roomChatMessages"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "roomChatConversations", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "roomChatConversations"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "unreadMessageCount", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "unreadMessageCount"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "chatConvasationUserUuid", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "chatConvasationUserUuid"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "chatConvasationMessageId", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "chatConvasationMessageId"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "roomChatMessagesMessageId", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "roomChatMessagesMessageId"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "newMessageFlag", [_mobx.computed], Object.getOwnPropertyDescriptor(_class.prototype, "newMessageFlag"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "addChatMessage", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "addChatMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "addRoomChatConversation", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "addRoomChatConversation"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "addConversationChatMessage", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "addConversationChatMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "getHistoryChatMessage", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "getHistoryChatMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "getConversationHistoryChatMessage", [_dec5], Object.getOwnPropertyDescriptor(_class.prototype, "getConversationHistoryChatMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "getConversationList", [_dec6], Object.getOwnPropertyDescriptor(_class.prototype, "getConversationList"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "muteChat", [_dec7], Object.getOwnPropertyDescriptor(_class.prototype, "muteChat"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "unmuteChat", [_dec8], Object.getOwnPropertyDescriptor(_class.prototype, "unmuteChat"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "resetUnreadMessageCount", [_dec9], Object.getOwnPropertyDescriptor(_class.prototype, "resetUnreadMessageCount"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "incrementUnreadMessageCount", [_dec0], Object.getOwnPropertyDescriptor(_class.prototype, "incrementUnreadMessageCount"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "sendMessage", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class.prototype, "sendMessage"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "sendMessageToConversation", [_agoraRteSdk.bound], Object.getOwnPropertyDescriptor(_class.prototype, "sendMessageToConversation"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_setEventHandler", [_mobx.action], Object.getOwnPropertyDescriptor(_class.prototype, "_setEventHandler"), _class.prototype), _class);
let SceneEventHandler = (_dec1 = _mobx.action.bound, _dec10 = _mobx.action.bound, _dec11 = _mobx.action.bound, _dec12 = _mobx.action.bound, _dec13 = _mobx.action.bound, _dec14 = _mobx.action.bound, _class2 = (_SceneEventHandler = class SceneEventHandler {
static createEventHandler(scene) {
if (SceneEventHandler._handlers[scene.sceneId]) {
SceneEventHandler._handlers[scene.sceneId].removeEventHandlers();
}
const handler = new SceneEventHandler(scene);
handler.addEventHandlers();
SceneEventHandler._handlers[scene.sceneId] = handler;
return SceneEventHandler._handlers[scene.sceneId];
}
static getEventHandler(scene) {
return SceneEventHandler._handlers[scene.sceneId];
}
static cleanup() {
Object.keys(SceneEventHandler._handlers).forEach(k => {
SceneEventHandler._handlers[k].removeEventHandlers();
});
SceneEventHandler._handlers = {};
}
constructor(_scene) {
this._scene = _scene;
_initializerDefineProperty(this, "dataStore", _descriptor2, this);
}
addEventHandlers() {
this._scene.on(_agoraRteSdk.AgoraRteEventType.ChatUserMessage, this._receiveUserMessage);
this._scene.on(_agoraRteSdk.AgoraRteEventType.ChatReceived, this._receiveChat);
this._scene.on(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange);
}
removeEventHandlers() {
this._scene.off(_agoraRteSdk.AgoraRteEventType.ChatUserMessage, this._receiveUserMessage);
this._scene.off(_agoraRteSdk.AgoraRteEventType.ChatReceived, this._receiveChat);
this._scene.off(_agoraRteSdk.AgoraRteEventType.RoomPropertyUpdated, this._handleRoomPropertiesChange);
}
_handleRoomPropertiesChange(changedRoomProperties, roomProperties, operator, cause) {
changedRoomProperties.forEach(key => {
if (key === 'muteChat') {
this.dataStore.chatMuted = !!(0, _get.default)(roomProperties, 'muteChat', 0);
}
});
}
_receiveChat(evt) {
const {
userUuid: currentUserUuid,
roomType
} = _configs.EduClassroomConfig.shared.sessionInfo;
(0, _mobx.runInAction)(() => {
var _evt$ext;
const {
sendTime,
messageId,
message: chatMessage
} = evt;
let {
fromUser: {
userUuid,
userName
}
} = evt;
const {
fromUser: {
role
}
} = evt;
const isBroadcast = ((_evt$ext = evt.ext) === null || _evt$ext === void 0 ? void 0 : _evt$ext.range) === 3;
if (isBroadcast) {
userUuid = evt.ext.userUuid;
userName = evt.ext.userName;
}
const messageItem = new _struct.MessageItem({
id: userUuid,
ts: sendTime,
messageId: messageId,
content: chatMessage,
userName,
role: (0, _utils.RteRole2EduRole)(roomType, role),
isOwn: userUuid === currentUserUuid,
isBroadcast
});
this.addChatMessage(messageItem);
this.dataStore.newMessageFlag = true;
});
}
addChatMessage(args) {
this.dataStore.roomChatMessages.push(args);
this.dataStore.roomChatMessagesMessageId.set(args.messageId, args);
}
_receiveUserMessage(evt) {
const {
userUuid,
userName,
role,
roomType
} = _configs.EduClassroomConfig.shared.sessionInfo;
(0, _mobx.runInAction)(() => {
const {
fromUser,
sendTime,
messageId,
message: chatMessage
} = evt;
const conversationMessageItem = new _struct.MessageItem({
id: fromUser.userUuid,
userName: fromUser.userName,
ts: sendTime,
messageId: messageId,
content: chatMessage,
role: (0, _utils.RteRole2EduRole)(roomType, fromUser.role),
isOwn: userUuid == fromUser.userUuid,
isBroadcast: false
});
const conversationItem = {
// use from info
userName: fromUser.userName,
userUuid: fromUser.userUuid,
unreadMessageCount: 0,
messages: [conversationMessageItem]
};
if (role === _type.EduRoleTypeEnum.student) {
conversationItem.userName = userName;
conversationItem.userUuid = userUuid;
}
const conversationList = new _struct.Conversation(conversationItem);
this.addConversationChatMessage(conversationMessageItem, conversationList);
this.dataStore.newMessageFlag = true;
});
}
addRoomChatConversation(conversation) {
this.dataStore.roomChatConversations.push(conversation);
this.dataStore.chatConvasationUserUuid.set(conversation.userUuid, conversation);
conversation.messages.forEach(message => {
this.dataStore.chatConvasationMessageId.set(message.messageId, message);
});
}
addConversationChatMessage(args, conversation) {
const chatConversation = this.dataStore.chatConvasationUserUuid.get(conversation.userUuid);
if (!chatConversation) {
this.addRoomChatConversation(conversation);
} else {
!this.dataStore.chatConvasationMessageId.has(args.messageId) && chatConversation.messages.push(args);
}
}
}, _SceneEventHandler._handlers = {}, _SceneEventHandler), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, "dataStore", [_mobx.observable], {
configurable: true,
enumerable: true,
writable: true,
initializer: function () {
return {
roomChatMessages: [],
roomChatConversations: [],
unreadMessageCount: 0,
chatConvasationUserUuid: new Map(),
chatConvasationMessageId: new Map(),
roomChatMessagesMessageId: new Map(),
newMessageFlag: false,
chatMuted: false
};
}
}), _applyDecoratedDescriptor(_class2.prototype, "_handleRoomPropertiesChange", [_dec1], Object.getOwnPropertyDescriptor(_class2.prototype, "_handleRoomPropertiesChange"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_receiveChat", [_dec10], Object.getOwnPropertyDescriptor(_class2.prototype, "_receiveChat"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "addChatMessage", [_dec11], Object.getOwnPropertyDescriptor(_class2.prototype, "addChatMessage"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "_receiveUserMessage", [_dec12], Object.getOwnPropertyDescriptor(_class2.prototype, "_receiveUserMessage"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "addRoomChatConversation", [_dec13], Object.getOwnPropertyDescriptor(_class2.prototype, "addRoomChatConversation"), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, "addConversationChatMessage", [_dec14], Object.getOwnPropertyDescriptor(_class2.prototype, "addConversationChatMessage"), _class2.prototype), _class2);