protected override async Task InitializeForNewStudySessionAsync( MultiLineTextList multiLineTexts) { #region DisableNav/Thinking DisableNavigationRequestedEventMessage.Publish(); var targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); #endregion try { #region ThinkPing History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); #endregion var retrieverStudyData = await Business.StudyDataRetriever.CreateNewAsync(); _CurrentUserNativeLanguageText = retrieverStudyData.StudyData.NativeLanguageText; #region ThinkPing History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); #endregion var retrieverRecentBeliefs = await MostRecentPhraseDataBeliefsRetriever.CreateNewAsync(); _MostRecentPhraseBeliefsCache = retrieverRecentBeliefs.MostRecentPhraseBeliefs; #region ThinkPing History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); #endregion } finally { #region EnableNav/Thinked EnableNavigationRequestedEventMessage.Publish(); History.Events.ThinkedAboutTargetEvent.Publish(targetId); #endregion } }
/// <summary> /// Unregistered means not registered in either beliefs from cache or pseudo beliefs from cache. /// </summary> /// <param name="multiLineTextList"></param> /// <param name="unknownBeliefsFromCache"></param> /// <param name="unknownPseudoBeliefsFromCache"></param> /// <returns></returns> private List <PhraseEdit> GetUnregisteredUnknownPhraseBeliefs(MultiLineTextList multiLineTextList, List <PhraseBeliefEdit> unknownBeliefsFromCache, List <KeyValuePair <string, Tuple <string, double> > > unknownPseudoBeliefsFromCache) { List <PhraseEdit> retPhrases = new List <PhraseEdit>(); foreach (var mlt in multiLineTextList) { var phrasesInNeitherCache = from line in mlt.Lines where //LINE IS NOT IN EITHER CACHE (THUS EXCLUDING ASSOCIATED UNKNOWN BELIEFS) (!(from keyIsPhraseText in unknownPseudoBeliefsFromCache select keyIsPhraseText.Key).Union( from belief in unknownBeliefsFromCache select belief.Phrase.Text).Contains(line.Phrase.Text)) && //AND PHRASE HAS NO ASSOCIATED BELIEF (THUS EXCLUDING KNOWN BELIEFS) (!(from keyIsPhraseText in _PseudoBeliefsCache select keyIsPhraseText.Key).Union( from belief in _MostRecentPhraseBeliefsCache select belief.Phrase.Text).Contains(line.Phrase.Text)) select line.Phrase; retPhrases.AddRange(phrasesInNeitherCache); } return(retPhrases); }
public async Task GET() { Guid testId = Guid.Empty; MultiLineTextEdit multiLineTextEdit = null; var isAsyncComplete = false; var hasError = false; EnqueueConditional(() => isAsyncComplete); await Setup(); try { var allMultiLineTexts = await MultiLineTextList.GetAllAsync(); testId = allMultiLineTexts.First().Id; multiLineTextEdit = await MultiLineTextEdit.GetMultiLineTextEditAsync(testId); } catch { hasError = true; } finally { EnqueueCallback( () => Assert.IsFalse(hasError), () => Assert.IsNotNull(multiLineTextEdit), () => Assert.IsTrue(multiLineTextEdit.Lines.Count >= 2), () => Assert.AreEqual(testId, multiLineTextEdit.Id) ); EnqueueTestComplete(); Teardown(); isAsyncComplete = true; } }
private bool PhraseTextIsInMultiLineTextList(string phraseText, MultiLineTextList multiLineTextList) { var exists = (from mlt in multiLineTextList where (from line in mlt.Lines where line.Phrase.Text == phraseText select line).Count() > 0 select mlt).Count() > 0; return(exists); }
/// <summary> /// Simply gets the phrase from a random line from any of the MultiLineTexts /// in the given multiLineTextList parameter. /// </summary> /// <returns></returns> private PhraseEdit GetRandomPhrase(MultiLineTextList multiLineTextList) { var relevantBeliefs = PhraseBeliefList.GetBeliefsAboutPhrasesInMultiLineTextsAsync(multiLineTextList); var randomMlt = RandomPicker.Ton.PickOne <MultiLineTextEdit>(multiLineTextList); var randomLine = RandomPicker.Ton.PickOne <LineEdit>(randomMlt.Lines); return(randomLine.Phrase); }
/// <summary> /// This method is called when the user presses the Go button. /// </summary> public async Task Go() { var ids = new MobileList <Guid>(); foreach (var songViewModel in Items) { if (songViewModel.IsChecked) { ids.Add(songViewModel.Model.Id); } } //var targetId = new Guid(@"5D4355FE-C46E-4AA1-9E4A-45288C341C44"); var targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); var songs = await MultiLineTextList.NewMultiLineTextListAsync(ids); History.Events.ThinkedAboutTargetEvent.Publish(targetId); var nativeLanguage = await LanguageEdit.GetLanguageEditAsync(GetNativeLanguageText()); var noExpirationDate = StudyJobInfo <MultiLineTextList, IViewModelBase> .NoExpirationDate; var precision = double.Parse(AppResources.DefaultExpectedPrecision); //CREATE JOB INFO var studyJobInfo = new StudyJobInfo <MultiLineTextList, IViewModelBase>(songs, nativeLanguage, noExpirationDate, precision); //CREATE OPPORTUNITY var opportunity = new Opportunity <MultiLineTextList, IViewModelBase>(Id, this, studyJobInfo, StudyResources.CategoryStudy); //ADD OPPORTUNITY TO OUR FUTURE OPPORTUNITIES FutureOpportunities.Add(opportunity); //LET THE HISTORY SHOW THAT YOU ARE THINKING ABOUT THIS OPPORTUNITY var opportunityId = opportunity.Id; History.Events.ThinkingAboutTargetEvent.Publish(opportunityId); //PUBLISH THE OPPORTUNITY Exchange.Ton.Publish(opportunity); //NOW, WE WAIT UNTIL WE HEAR A HANDLE(OFFER) MESSAGE. //TODO: TIMEOUT FOR OPPORTUNITY, BOTH EXPIRATION DATE AND WAITING FOR OFFER TIMEOUT }
protected abstract Task InitializeForNewStudySessionAsync(MultiLineTextList multiLineTexts);
protected virtual async Task StudyAsync(MultiLineTextList multiLineTexts) { _AbortIsFlagged = false; StudyItemViewModelBase contentVM = null; IFeedbackViewModelBase feedbackVM = _ViewModel.FeedbackViewModel; ///INITIALIZE HISTORY PUBLISHER History.HistoryPublisher.Ton.PublishEvent(new StartingStudySessionEvent()); ///OKAY, SO AT THIS POINT, WE HAVE DONE OUR WORK THROUGH THE EXCHANGE. ///THE CALLER HAS A REFERENCE TO OUR _VIEWMODEL PROPERTY. WE HAVE CONTROL ///OF THE STUDY PROCESS THROUGH THIS _VIEWMODEL PROPERTY. WE USE TWO SUB VIEWMODELS ///AT THIS POINT: STUDYITEM VIEWMODEL, AND FEEDBACK VIEWMODEL. WE WILL IGNORE TIMEOUTS ///TO SIMPLIFY THINGS. WE JUST NEED TO DO A FEW THINGS: ///1) INITIALIZE FOR OUR STUDY SESSION ///2) GET NEXT/ ASSIGN _VIEWMODEL.STUDYITEMVIEWMODEL AND _VIEWMODEL.FEEDBACKVIEWMODEL. ///3) SHOW STUDYITEMVIEWMODEL. ///4) WHEN SHOW IS DONE, ENABLE FEEDBACK VIEWMODEL AND GET FEEDBACK #region Thinking (try..) var targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); try { #endregion ///1) INITIALIZE FOR OUR STUDY SESSION await InitializeForNewStudySessionAsync(multiLineTexts); #region (...finally) Thinked } finally { History.Events.ThinkedAboutTargetEvent.Publish(targetId); } #endregion //STUDY SESSION LOOP while (!_CompleteIsFlagged && !_AbortIsFlagged) { //BEGINNING OF A SINGLE STUDY ITEM _IsStudying = true; _ViewModel.FeedbackViewModel.IsEnabled = false; ///2) GET NEXT/ ASSIGN _VIEWMODEL.STUDYITEMVIEWMODEL AND _VIEWMODEL.FEEDBACKVIEWMODEL. History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); //STUDY ITEM VIEWMODEL CONTENT _ViewModel.StudyItemViewModel = await GetNextStudyItemViewModelAsync(); History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); contentVM = _ViewModel.StudyItemViewModel; if (contentVM == null) { //IF WE CAN'T GET A NEW STUDY ITEM VIEWMODEL, THEN THE STUDY SESSION IS COMPLETED. _CompleteIsFlagged = true; break; } #region Abort Check if (_AbortIsFlagged) { _IsStudying = false; break; } #endregion ///3) SHOW STUDY ITEM VIEWMODEL. /// DO *NOT* THINK BEFORE AFTER, CAUSE THIS IS WAITING FOR USER INPUT await contentVM.ShowAsync(); #region Abort Check if (_AbortIsFlagged) { _IsStudying = false; break; } #endregion ///4) WHEN SHOW IS DONE, GET FEEDBACK History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); var feedbackTimeout = int.Parse(StudyResources.DefaultFeedbackTimeoutMilliseconds); var feedback = await feedbackVM.GetFeedbackAsync(feedbackTimeout); History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); //RIGHT NOW I'M NOT DOING ANYTHING WITH THIS FEEDBACK, AS IT IS PUBLISHED WHEN //IT IS CREATED BY THE FEEDBACKVM. I'M JUST KEEPING IT HERE TO SHOW THAT I CAN //GET THE FEEDBACK HERE. THERE MIGHT BE A BETTER WAY TO DO THIS ANYWAY. #region Abort Check if (_AbortIsFlagged) { _IsStudying = false; break; } #endregion } }
/// <summary> /// This method is called when the user presses the Go button. /// </summary> public async Task Go() { if (!CanGo) { return; } DisableNavigationRequestedEventMessage.Publish(); GoInProgress = true; try { var ids = new MobileList <Guid>(); foreach (var songViewModel in Items) { if (songViewModel.IsChecked) { Guid id = default(Guid); var results = from entry in _MultiLineTextIdsAndTitles where entry.Value == songViewModel.SongTitle select entry; id = results.First().Key; ids.Add(id); } } MultiLineTextList songs = null; #region Try ...(thinking) //var targetId = new Guid(@"5D4355FE-C46E-4AA1-9E4A-45288C341C44"); var targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); try { #endregion songs = await MultiLineTextList.NewMultiLineTextListAsync(ids); #region ...Finally (thinked) } finally { History.Events.ThinkedAboutTargetEvent.Publish(targetId); } #endregion var nativeLanguage = await LanguageEdit.GetLanguageEditAsync(GetNativeLanguageText()); var noExpirationDate = StudyJobInfo <MultiLineTextList, IViewModelBase> .NoExpirationDate; var precision = double.Parse(StudyResources.DefaultExpectedPrecision); //CREATE JOB INFO var studyJobInfo = new StudyJobInfo <MultiLineTextList, IViewModelBase>(songs, nativeLanguage, noExpirationDate, precision); //CREATE OPPORTUNITY var opportunity = new Opportunity <MultiLineTextList, IViewModelBase>(Id, this, studyJobInfo, StudyResources.CategoryStudy); //ADD OPPORTUNITY TO OUR FUTURE OPPORTUNITIES FutureOpportunities.Add(opportunity); //LET THE HISTORY SHOW THAT YOU ARE THINKING ABOUT THIS OPPORTUNITY var opportunityId = opportunity.Id; History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); //PUBLISH THE OPPORTUNITY Exchange.Ton.Publish(opportunity); //NOW, WE WAIT UNTIL WE HEAR A HANDLE(OFFER) MESSAGE. //TODO: TIMEOUT FOR OPPORTUNITY, BOTH EXPIRATION DATE AND WAITING FOR OFFER TIMEOUT } finally { EnableNavigationRequestedEventMessage.Publish(); } }
/// <summary> /// Gets the most recent phrase beliefs for all of the current user's phrases. /// </summary> /// <returns></returns> private async Task <PhraseEdit> GetRandomUnknownPhrase(MultiLineTextList multiLineTextList) { History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); if (_MostRecentPhraseBeliefsCache == null) { throw new Exception("MostRecentPhraseBeliefsCache should not be null"); } if (_PseudoBeliefsCache == null) { _PseudoBeliefsCache = new MobileDictionary <string, Tuple <string, double> >(); } PhraseEdit retPhrase = null; //GET OUR UNKNOWNS OUT OF OUR CACHES var threshold = double.Parse(StudyResources.DefaultKnowledgeThreshold); var unknownBeliefsFromCache = (from belief in _MostRecentPhraseBeliefsCache where belief.Strength < threshold && PhraseTextIsInMultiLineTextList(belief.Phrase.Text, multiLineTextList) select belief).ToList(); var unknownPseudoBeliefsFromCache = (from entry in _PseudoBeliefsCache where entry.Value.Item2 < threshold && PhraseTextIsInMultiLineTextList(entry.Key, multiLineTextList) select entry).ToList(); //GET OUR UNKNOWN PHRASES THAT DONT HAVE A BELIEF OR PSUEDO BELIEF REGISTERED WITH THEM YET var unregisteredUnknownPhrases = GetUnregisteredUnknownPhraseBeliefs(multiLineTextList, unknownBeliefsFromCache, unknownPseudoBeliefsFromCache); var indexToPick = -1; //TOTAL COUNT = MOST RECENT PHRASE BELIEFS + PSEUDO BELIEFS COUNT + PHRASES WITHOUT BELIEFS var totalCountUnknown = 0; totalCountUnknown += unknownBeliefsFromCache.Count; if (_PseudoBeliefsCache != null) { totalCountUnknown += unknownPseudoBeliefsFromCache.Count; } totalCountUnknown += unregisteredUnknownPhrases.Count; if (totalCountUnknown == 0) { //EVERYTHING IS KNOWN, SO RETURN NULL return(null); } //IF WE TRY TO PICK FROM THE PSEUDO CACHE, THEN IT IS POSSIBLE //THAT OUR PHRASETEXT NO LONGER MATCHES A PHRASE. THEREFORE, WE //SET UP A LOOP TO KEEP TRYING TO PICK A RANDOM PHRASE FROM THE //ENTIRE LIST OF BOTH CACHES. IF WE FAIL TO DO THIS, THEN WE WILL //PICK FROM JUST THE ACTUAL BELIEF CACHE (NOT THE PSEUDO). var maxTries = int.Parse(StudyResources.MaxTriesToPickRandomFromEntireList); for (int i = 0; i < maxTries; i++) { History.Events.ThinkingAboutTargetEvent.Publish(System.Guid.Empty); indexToPick = RandomPicker.Ton.NextInt(0, totalCountUnknown); if (indexToPick < unknownBeliefsFromCache.Count) { //WE PICK FROM THE PHRASE BELIEF CACHE var belief = unknownBeliefsFromCache[indexToPick]; return(belief.Phrase); } else if (indexToPick < (unknownBeliefsFromCache.Count + unknownPseudoBeliefsFromCache.Count)) { //WE _TRY_ TO PICK FROM THE PSUEDO CACHE indexToPick -= unknownBeliefsFromCache.Count; var beliefEntry = unknownPseudoBeliefsFromCache[indexToPick]; var phraseText = beliefEntry.Key; var languageText = beliefEntry.Value.Item1; var phrase = await PhraseEdit.NewPhraseEditAsync(languageText); phrase.Text = phraseText; var phraseId = Guid.NewGuid(); phrase.Id = phraseId; var retriever = await PhrasesByTextAndLanguageRetriever.CreateNewAsync(phrase); retPhrase = retriever.RetrievedSinglePhrase; if (retPhrase != null) { //WE HAVE FOUND A RETURN PHRASE, SO BREAK OUT OF OUR ATTEMPT LOOP return(retPhrase); } } else { //WE PICK FROM THE UNKNOWN PHRASES WITHOUT BELIEFS I'M CONVERTING THIS //TO LIST THIS LATE BECAUSE WE DON'T NEED IT AS A LIST UNTIL NOW. var asList = unregisteredUnknownPhrases.ToList(); indexToPick -= (unknownBeliefsFromCache.Count + unknownPseudoBeliefsFromCache.Count); retPhrase = unregisteredUnknownPhrases[indexToPick]; return(retPhrase); } } //IF WE'VE GOTTEN THIS FAR, THEN WE COULDN'T FIND AN UNKNOWN PHRASE Services.PublishMessageEvent("Couldn't retrieve unknown phrase.", MessagePriority.Medium, MessageType.Warning); return(null); }
/// <summary> /// Gets all songs in DB for this user, and calls PopulateItems. /// </summary> private async Task StartPopulateAllSongsAsync() { #region Thinking var targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); #endregion var allMultiLineTexts = await MultiLineTextList.GetAllAsync(); History.Events.ThinkedAboutTargetEvent.Publish(targetId); #region Sort MLT by Title Comparison (Comparison<MultiLineTextEdit> comparison = (a, b) =>) Comparison <MultiLineTextEdit> comparison = (a, b) => { //WE'RE GOING TO TEST CHAR ORDER IN ALPHABET string aTitle = a.Title.ToLower(); string bTitle = b.Title.ToLower(); //IF THEY'RE THE SAME TITLES IN LOWER CASE, THEN THEY ARE EQUAL if (aTitle == bTitle) { return(0); } //ONLY NEED TO TEST CHARACTERS UP TO LENGTH int shorterTitleLength = aTitle.Length; bool aIsShorter = true; if (bTitle.Length < shorterTitleLength) { shorterTitleLength = bTitle.Length; aIsShorter = false; } int result = 0; //assume a and b are equal (though we know they aren't if we've reached this point) for (int i = 0; i < shorterTitleLength; i++) { if (aTitle[i] < bTitle[i]) { result = -1; break; } else if (aTitle[i] > bTitle[i]) { result = 1; break; } } //IF THEY ARE STILL EQUAL, THEN THE SHORTER PRECEDES THE LONGER if (result == 0) { if (aIsShorter) { result = -1; } else { result = 1; } } return(result); }; #endregion ModelList = allMultiLineTexts; List <MultiLineTextEdit> songs = null; #region Thinking (try..) targetId = Guid.NewGuid(); History.Events.ThinkingAboutTargetEvent.Publish(targetId); try { #endregion songs = (from multiLineText in allMultiLineTexts where multiLineText.AdditionalMetadata.Contains(MultiLineTextEdit.MetadataEntrySong) select multiLineText).ToList(); songs.Sort(comparison); #region (...finally) Thinked } finally { History.Events.ThinkedAboutTargetEvent.Publish(targetId); } #endregion //CACHE ALL SONGS SO WE WON'T HAVE TO DOWNLOAD THEM AGAIN. THIS IS ASSUMING MY CURRENT NAVIGATION //STRUCTURE WHICH MEANS THAT YOU CAN'T ADD SONGS WITHOUT RECREATING THIS ENTIRE VIEWMODEL. //THIS CACHE WILL BE USED FOR FILTERING. SortedModelListCache = songs; PopulateItems(); }