|
@@ -0,0 +1,462 @@
|
|
|
+using Azure.Cosmos;
|
|
|
+using HTEXLib.COMM.Helpers;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using TEAMModelOS.SDK.DI;
|
|
|
+using TEAMModelOS.SDK.Models;
|
|
|
+
|
|
|
+namespace TEAMModelOS.SDK
|
|
|
+{
|
|
|
+ public static class StatisticsService
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// 视频观看记录
|
|
|
+ /// </summary>
|
|
|
+ public const string VideoRecord= "VideoRecord";
|
|
|
+ /// <summary>
|
|
|
+ /// 教师能力点操作
|
|
|
+ /// </summary>
|
|
|
+ public const string TeacherAility = "TeacherAility";
|
|
|
+ /// <summary>
|
|
|
+ /// 课堂实录
|
|
|
+ /// </summary>
|
|
|
+ public const string TeacherClass = "TeacherClass";
|
|
|
+ /// <summary>
|
|
|
+ /// 线下研修
|
|
|
+ /// </summary>
|
|
|
+ public const string OfflineRecord = "OfflineRecord";
|
|
|
+ public static async Task<List<TeacherTrain> > StatisticsArea(AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing)
|
|
|
+ {
|
|
|
+ List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
|
|
|
+ List<School> schools = new List<School>();
|
|
|
+ await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School")
|
|
|
+ .GetItemQueryIterator<School>(queryText: $"select value(c) from c where c.areaId='{area.id}' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base") }))
|
|
|
+ {
|
|
|
+ schools.Add(item);
|
|
|
+ }
|
|
|
+ await foreach (var tarain in GetStatisticsSchool(schools, setting, area, client,_dingDing))
|
|
|
+ {
|
|
|
+ teacherTrains.AddRange(tarain);
|
|
|
+ }
|
|
|
+ return teacherTrains;
|
|
|
+ }
|
|
|
+ private static async IAsyncEnumerable<List<TeacherTrain>> GetStatisticsSchool(List<School> schools, AreaSetting setting, Area area, CosmosClient client, DingDing _dingDing)
|
|
|
+ {
|
|
|
+ foreach (var school in schools)
|
|
|
+ {
|
|
|
+ yield return await StatisticsSchool(school.id, setting, area, client,_dingDing);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public static async Task<List<TeacherTrain>> StatisticsSchool(string school, AreaSetting setting, Area area, CosmosClient client,DingDing _dingDing) {
|
|
|
+ List<RGroupList> yxtrain = await GroupListService.GetGroupListMemberByType(client, "yxtrain", new List<string> { "school" }, $"{school}", _dingDing);
|
|
|
+ List<TeacherTrain> trains = new List<TeacherTrain>();
|
|
|
+ await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
|
|
|
+ .GetItemQueryIterator<TeacherTrain>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{school}") })) {
|
|
|
+ trains.Add(item);
|
|
|
+ }
|
|
|
+ var update = trains.FindAll(x => x.updateProperty.Count() > 0);
|
|
|
+ var noupdate = trains.FindAll(x => x.updateProperty.Count() <=0);
|
|
|
+ var members= yxtrain.SelectMany(x => x.members);
|
|
|
+ var unStatistics = members.Select(x => x.id).Except(trains.Select(x => x.id));
|
|
|
+ List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
|
|
|
+ List<TeacherTrain> returnTrains = new List<TeacherTrain>();
|
|
|
+ if (update.IsNotEmpty()) {
|
|
|
+ teacherTrains.AddRange(update);
|
|
|
+ }
|
|
|
+ if (unStatistics != null) {
|
|
|
+ foreach (string x in unStatistics) {
|
|
|
+ teacherTrains.Add(new TeacherTrain
|
|
|
+ {
|
|
|
+ id = x,
|
|
|
+ code = $"TeacherTrain-{school}",
|
|
|
+ tmdid = x,
|
|
|
+ school = school,
|
|
|
+ updateProperty = new HashSet<string> { VideoRecord,TeacherAility,TeacherClass,OfflineRecord }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ await foreach (var tarain in GetStatisticsTeacher(teacherTrains, setting, area, client))
|
|
|
+ {
|
|
|
+ returnTrains.Add(tarain);
|
|
|
+ }
|
|
|
+ if (noupdate.IsNotEmpty()) {
|
|
|
+ returnTrains.AddRange(noupdate);
|
|
|
+ }
|
|
|
+ return returnTrains;
|
|
|
+ }
|
|
|
+ private static async IAsyncEnumerable<TeacherTrain> GetStatisticsTeacher(List<TeacherTrain> trains, AreaSetting setting, Area area, CosmosClient client)
|
|
|
+ {
|
|
|
+ foreach (var train in trains)
|
|
|
+ {
|
|
|
+ yield return await StatisticsTeacher( train, setting, area, client);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public static async Task<TeacherTrain> StatisticsTeacher(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client) {
|
|
|
+ string _school = train.school;
|
|
|
+ string _tmdid = train.tmdid;
|
|
|
+ TeacherTrain teacher_train = null;
|
|
|
+ if (train.updateProperty.Count > 0) {
|
|
|
+ await foreach (var tarain in DoProperty(train.updateProperty, setting, area, client, train)){
|
|
|
+ teacher_train=tarain;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //每次都统计活动相关的数据。
|
|
|
+ train= await DoActivity(train, setting, area, client, _school, _tmdid);
|
|
|
+ train.totalTime = train.onlineTime + train.classTime + train.submitTime + train.offlineTime;
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+ private static async IAsyncEnumerable<TeacherTrain> DoProperty(HashSet<string> updateProperty, AreaSetting setting, Area area, CosmosClient client, TeacherTrain train )
|
|
|
+ {
|
|
|
+ string _school = train.school;
|
|
|
+ string _tmdid = train.tmdid;
|
|
|
+ foreach (var property in updateProperty)
|
|
|
+ {
|
|
|
+ //视频观看更新
|
|
|
+ if (property.Equals(VideoRecord, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ train = await DoVideoRecord(train, setting, area, client, _school, _tmdid);
|
|
|
+ train.updateProperty.Remove(VideoRecord);
|
|
|
+ yield return train;
|
|
|
+ }
|
|
|
+ //认证材料更新
|
|
|
+ if (property.Equals(TeacherAility, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ train = await DoTeacherAility(train, setting, area, client, _school, _tmdid);
|
|
|
+ train.updateProperty.Remove(TeacherAility);
|
|
|
+ yield return train;
|
|
|
+ }
|
|
|
+ //课堂实录更新
|
|
|
+ if (property.Equals(TeacherClass, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ train = await DoTeacherClass(train, setting, area, client, _school, _tmdid);
|
|
|
+ train.updateProperty.Remove(TeacherClass);
|
|
|
+ yield return train;
|
|
|
+ }
|
|
|
+ //线下研修
|
|
|
+ if (property.Equals(OfflineRecord, StringComparison.OrdinalIgnoreCase))
|
|
|
+ {
|
|
|
+ train = await DoOfflineRecord(train, setting, area, client, _school, _tmdid);
|
|
|
+ train.updateProperty.Remove(OfflineRecord);
|
|
|
+ yield return train;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public static async Task<TeacherTrain> DoActivity(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
|
|
|
+ //问卷调查
|
|
|
+ await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher")
|
|
|
+ .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Survey' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(item.owner))
|
|
|
+ {
|
|
|
+ if (item.owner.Equals("school"))
|
|
|
+ {
|
|
|
+ train.surveyJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.surveyDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (item.owner.Equals("area"))
|
|
|
+ {
|
|
|
+ train.surveyAreaJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.surveyAreaDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //评量检测
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
|
|
|
+ .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'ExamLite' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(item.owner))
|
|
|
+ {
|
|
|
+ if (item.owner.Equals("school"))
|
|
|
+ {
|
|
|
+ train.examJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.examDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (item.owner.Equals("area"))
|
|
|
+ {
|
|
|
+ train.examAreaJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.examAreaDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //投票活动
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
|
|
|
+ .GetItemQueryIterator<StuActivity>(queryText: $"select c.owner, c.taskStatus from c where c.type = 'Vote' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(item.owner))
|
|
|
+ {
|
|
|
+ if (item.owner.Equals("school"))
|
|
|
+ {
|
|
|
+ train.voteJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.voteDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (item.owner.Equals("area"))
|
|
|
+ {
|
|
|
+ train.voteAreaJoin += 1;
|
|
|
+ if (item.taskStatus > 0)
|
|
|
+ {
|
|
|
+ train.voteAreaDone += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 课堂实录更新
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="train"></param>
|
|
|
+ /// <param name="setting"></param>
|
|
|
+ /// <param name="area"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <param name="_school"></param>
|
|
|
+ /// <param name="_tmdid"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static async Task<TeacherTrain> DoOfflineRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
|
|
|
+ //owner: school area
|
|
|
+ //线下 学校研修活动
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
|
|
|
+ .GetItemQueryIterator<StuActivity>(queryText: $"select value(c) from c where c.type = 'Study' ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Activity-{_tmdid}") }))
|
|
|
+ {
|
|
|
+ Study study = null;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ study = await client.GetContainer("TEAMModelOS", "Common").ReadItemAsync<Study>(item.id, new PartitionKey(item.scode));
|
|
|
+ }
|
|
|
+ catch (CosmosException ex) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ StudyRecord studyRecord;
|
|
|
+
|
|
|
+ Attachment attachment = null;
|
|
|
+ try {
|
|
|
+ studyRecord= await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<StudyRecord>(item.id, new PartitionKey($"StudyRecord-{_tmdid}"));
|
|
|
+ }
|
|
|
+ catch (CosmosException ) {
|
|
|
+ studyRecord = null;
|
|
|
+ }
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(study.workId)) {
|
|
|
+ HomeworkRecord homeworkRecord = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<HomeworkRecord>(study.workId, new PartitionKey($"HomeworkRecord-{_tmdid}"));
|
|
|
+ attachment= homeworkRecord.content.Find(x => x.prime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (CosmosException)
|
|
|
+ {
|
|
|
+ attachment = null;
|
|
|
+ }
|
|
|
+ if (!string.IsNullOrEmpty(item.owner))
|
|
|
+ {
|
|
|
+ OfflineRecord record = new OfflineRecord
|
|
|
+ {
|
|
|
+ id = item.id,
|
|
|
+ name = item.name,
|
|
|
+ done = item.taskStatus,
|
|
|
+ owner = item.owner
|
|
|
+ };
|
|
|
+ if (null != studyRecord)
|
|
|
+ {
|
|
|
+ //通过获得学时
|
|
|
+ record.hour = studyRecord.status == 1 ? study.hour : 0;
|
|
|
+ train.offlineTime = record.hour;
|
|
|
+ if (studyRecord.status == 1)
|
|
|
+ {
|
|
|
+ record.score = 1;
|
|
|
+ record.done = 1;
|
|
|
+ }
|
|
|
+ if (studyRecord.status == 0)
|
|
|
+ {
|
|
|
+ record.score = -1;
|
|
|
+ }
|
|
|
+ if (studyRecord.status == 2)
|
|
|
+ {
|
|
|
+ record.score = 0;
|
|
|
+ record.done = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (null != attachment)
|
|
|
+ {
|
|
|
+ record.url = attachment.url;
|
|
|
+ record.upload = 1;
|
|
|
+ record.hash = attachment.hash;
|
|
|
+ record.size = attachment.size;
|
|
|
+ }
|
|
|
+ train.offlineRecords.Add(record);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 课堂实录更新
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="train"></param>
|
|
|
+ /// <param name="setting"></param>
|
|
|
+ /// <param name="area"></param>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <param name="_school"></param>
|
|
|
+ /// <param name="_tmdid"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static async Task<TeacherTrain> DoTeacherClass(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid)
|
|
|
+ {
|
|
|
+ string code = $"ClassVideo-{_school}";
|
|
|
+ ClassVideo classVideo = await client.GetContainer("TEAMModelOS", "Teacher").ReadItemAsync<ClassVideo>($"{_tmdid}", new PartitionKey(code));
|
|
|
+ if (classVideo != null && classVideo.files.IsNotEmpty())
|
|
|
+ {
|
|
|
+ //2021.11.17 15:05,与J哥确认,取课堂实录第一个。前端也只show第一个视频。
|
|
|
+ var files = classVideo.files[0];
|
|
|
+ if (files.score > 0)
|
|
|
+ {
|
|
|
+ train.classTime += 5;
|
|
|
+ }
|
|
|
+ train.teacherClasses.Add(new Models.TeacherClass {url=files.url,score=files.score,hash=files.hash,name=files.name,size=files.size });
|
|
|
+ }
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+ public static async Task<TeacherTrain> DoVideoRecord(TeacherTrain train, AreaSetting setting, Area area, CosmosClient client, string _school, string _tmdid) {
|
|
|
+ TeacherFile file = null;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ file = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<TeacherFile>(_tmdid, new PartitionKey($"VideoRecord-{_school}"));
|
|
|
+ }
|
|
|
+ catch (CosmosException ex)
|
|
|
+ {
|
|
|
+ file = new TeacherFile
|
|
|
+ {
|
|
|
+ id = _tmdid,
|
|
|
+ code = $"VideoRecord-{_school}" ,
|
|
|
+ pk = "TeacherFile",
|
|
|
+ ttl = -1,
|
|
|
+
|
|
|
+ };
|
|
|
+ await client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherFile>(file, new PartitionKey($"VideoRecord-{_school}"));
|
|
|
+ }
|
|
|
+ if (file != null)
|
|
|
+ {
|
|
|
+ train.videoTime = file.fileRecords.Where(x => x.type.Equals("video")).Select(y => y.duration).Sum();
|
|
|
+ }
|
|
|
+ train.onlineTime = (int)train.videoTime / setting.lessonMinutes;
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+ public static async Task<TeacherTrain> DoTeacherAility(TeacherTrain train, AreaSetting setting,Area area , CosmosClient client,string _school,string _tmdid) {
|
|
|
+ await foreach (var item in client.GetContainer("TEAMModelOS", "Teacher")
|
|
|
+ .GetItemQueryIterator<AbilitySub>(queryText: $"select value(c) from c ", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"AbilitySub-{_school}-{_tmdid}") }))
|
|
|
+ {
|
|
|
+ int currency = item.from == 1 ? 1 : 0;
|
|
|
+ Ability ability = null;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ ability = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<Ability>(item.id, new PartitionKey($"Ability-{area.standard}"));
|
|
|
+ if (item.from == 0)
|
|
|
+ {
|
|
|
+ currency = ability.currency;
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ currency = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (CosmosException ex)
|
|
|
+ {
|
|
|
+ currency = 0;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (currency == 1) {
|
|
|
+ train.uploadTotal += ability.stds.FindAll(x=> x.task.IsNotEmpty()).Select(y=>y.task).Count();
|
|
|
+ if (item.uploads.IsNotEmpty())
|
|
|
+ {
|
|
|
+ train.uploadDone += item.uploads.Count;
|
|
|
+ }
|
|
|
+ train.subCount += 1;
|
|
|
+ if (item.exerciseScore > 0)
|
|
|
+ {
|
|
|
+ train.exerciseAbility += 1;
|
|
|
+ }
|
|
|
+ List<TeacherHprecord> hprecords = new List<TeacherHprecord>();
|
|
|
+ TeacherAility teacherAility = new Models.TeacherAility
|
|
|
+ {
|
|
|
+ id = ability.id,
|
|
|
+ currency = currency,
|
|
|
+ no = ability.no,
|
|
|
+ dimension = ability.dimension,
|
|
|
+ zpscore = item.self,
|
|
|
+ hprecord = hprecords,
|
|
|
+ uploadHas = item.uploads.Count
|
|
|
+ };
|
|
|
+ //train.learnAbility += item.abilityCount;
|
|
|
+ if (item.otherScore.IsNotEmpty())
|
|
|
+ {
|
|
|
+ var schoolScore = item.otherScore.Where(x => x.roleType.Equals("school")).FirstOrDefault();
|
|
|
+ if (schoolScore != null && schoolScore.score > 0)
|
|
|
+ {
|
|
|
+ teacherAility.xzscore = schoolScore.score;
|
|
|
+
|
|
|
+ }
|
|
|
+ var hprecord= item.otherScore.FindAll(x => x.roleType.Equals("member")).Select(y => new TeacherHprecord { tmdid = y.tmdid,tmdname=y.tmdname,score=y.score });
|
|
|
+ if (hprecord != null) {
|
|
|
+ var no = hprecord.Where(x => x.score == 0) != null ? hprecord.Where(x => x.score == 0).Count() : 0;
|
|
|
+ var hg = hprecord.Where(x => x.score == 1) != null ? hprecord.Where(x => x.score == 1).Count() : 0;
|
|
|
+ var yx = hprecord.Where(x => x.score == 2) != null ? hprecord.Where(x => x.score == 2).Count() : 0;
|
|
|
+ if (no == hg && hg == yx && no == 0)
|
|
|
+ {
|
|
|
+ teacherAility.hpscore = -1;
|
|
|
+ }
|
|
|
+ else if (no == hg && hg == yx && no != 0)
|
|
|
+ {
|
|
|
+ teacherAility.hpscore = 2;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ bool ok = false;
|
|
|
+ List<int> arr = new List<int>() { yx,hg,no};
|
|
|
+ int max = arr.Max();
|
|
|
+ if (max == yx && !ok) {
|
|
|
+ teacherAility.hpscore = 2;
|
|
|
+ ok = true;
|
|
|
+ }
|
|
|
+ if (max == hg && !ok)
|
|
|
+ {
|
|
|
+ teacherAility.hpscore = 1;
|
|
|
+ ok = true;
|
|
|
+ }
|
|
|
+ if (max == no && !ok)
|
|
|
+ {
|
|
|
+ teacherAility.hpscore = 0;
|
|
|
+ ok = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ teacherAility.hprecord.AddRange(hprecord);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ train.teacherAilities.Add(teacherAility);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var bhg = train.teacherAilities.FindAll(x => x.xzscore <= 0);
|
|
|
+ if (bhg.IsEmpty()) {
|
|
|
+ ///要全部合格才能获得学时。
|
|
|
+ train.submitTime = setting.submitTime;
|
|
|
+ }
|
|
|
+ return train;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|