├── .gitignore ├── BuildShell.ps1 ├── LICENSE ├── README.md └── src ├── Core ├── Amount.cs ├── AuthIdentity.cs ├── Categorization │ ├── Analyzer.cs │ ├── AnalyzerResult.cs │ ├── CategorizationEngine.cs │ ├── CategorizationResult.cs │ ├── Enums.cs │ ├── IDBLoader.cs │ ├── IIngredientCommonality.cs │ ├── IRecipeClassification.cs │ ├── IToken.cs │ ├── IngredientToken.cs │ ├── Ranking.cs │ ├── RecipeIndex.cs │ ├── TextToken.cs │ ├── TimeToken.cs │ └── Tokenizer.cs ├── Context │ ├── AlphaTree.cs │ ├── Configuration.cs │ ├── ConfigurationBuilder.cs │ ├── ConnectorVertex.cs │ ├── DBContext.cs │ ├── DBContextBuilder.cs │ ├── DBModelerLoader.cs │ ├── IConfiguration.cs │ ├── IConfigurationBuilder.cs │ ├── IDBAdapter.cs │ ├── IKPCContext.cs │ ├── ISearchProvider.cs │ ├── IngredientNode.cs │ ├── IngredientParser.cs │ ├── IngredientSource.cs │ ├── KPCContext.cs │ ├── StaticAnomalyLoader.cs │ ├── StaticContext.cs │ ├── StaticContextBuilder.cs │ ├── StaticFormLoader.cs │ ├── StaticIngredientLoader.cs │ ├── StaticModelerLoader.cs │ ├── StaticPrepLoader.cs │ ├── StaticSearch.cs │ └── StaticUnitLoader.cs ├── Core.csproj ├── Enums.cs ├── Exceptions.cs ├── Extensions.cs ├── Fluent │ ├── Menus.cs │ ├── Modeler.cs │ ├── Queue.cs │ ├── Recipes.cs │ └── ShoppingLists.cs ├── FormConversion.cs ├── Fractions.cs ├── Ingredients │ ├── Ingredient.cs │ ├── IngredientAggregation.cs │ ├── IngredientForm.cs │ ├── IngredientFormsCollection.cs │ ├── IngredientMetadata.cs │ ├── IngredientSection.cs │ ├── IngredientUsage.cs │ └── IngredientUsageCollection.cs ├── Linq │ └── Enumerable.cs ├── Menus │ ├── GetMenuOptions.cs │ ├── Menu.cs │ ├── MenuMove.cs │ └── MenuResult.cs ├── Modeler │ ├── CompiledModel.cs │ ├── DBSnapshot.cs │ ├── IModelerLoader.cs │ ├── IUserProfile.cs │ ├── IngredientBinding.cs │ ├── IngredientNode.cs │ ├── IngredientUsage.cs │ ├── Model.cs │ ├── ModelerProxy.cs │ ├── ModelerQuery.cs │ ├── ModelingSession.cs │ ├── PantryItem.cs │ ├── RatingBinding.cs │ ├── RatingGraph.cs │ ├── RecipeBinding.cs │ ├── RecipeNode.cs │ ├── RecipeRating.cs │ ├── SuggestedRecipe.cs │ └── UserProfile.cs ├── NLP │ ├── AlphaTree.cs │ ├── Anomalies.cs │ ├── AnomalousIngredientNode.cs │ ├── AnomalousMatch.cs │ ├── AnomalousNode.cs │ ├── ConnectorVertex.cs │ ├── CustomUnitNode.cs │ ├── DefaultPairings.cs │ ├── DefaultTracer.cs │ ├── Enums.cs │ ├── FormNode.cs │ ├── FormSynonyms.cs │ ├── IGrammar.cs │ ├── ISynonymLoader.cs │ ├── ITracer.cs │ ├── IngredientNode.cs │ ├── IngredientSynonyms.cs │ ├── Match.cs │ ├── MatchData.cs │ ├── NameIngredientPair.cs │ ├── NlpTracer.cs │ ├── NoMatch.cs │ ├── NumericNode.cs │ ├── NumericVocab.cs │ ├── Pairings.cs │ ├── Parser.cs │ ├── PartialMatch.cs │ ├── PrepNode.cs │ ├── PrepNotes.cs │ ├── Preps.cs │ ├── Result.cs │ ├── SynonymTree.cs │ ├── Template.cs │ ├── TemplateStatistics.cs │ ├── Tokens │ │ ├── AmtToken.cs │ │ ├── AnomToken.cs │ │ ├── FormToken.cs │ │ ├── IngToken.cs │ │ ├── NumericToken.cs │ │ ├── PrepToken.cs │ │ ├── StaticToken.cs │ │ └── UnitToken.cs │ ├── UnitNode.cs │ └── UnitSynonyms.cs ├── Properties │ └── AssemblyInfo.cs ├── Provisioning │ ├── DTO │ │ ├── Favorites.cs │ │ ├── IngredientForms.cs │ │ ├── IngredientMetadata.cs │ │ ├── Ingredients.cs │ │ ├── Menus.cs │ │ ├── NlpAnomalousIngredients.cs │ │ ├── NlpDefaultPairings.cs │ │ ├── NlpFormSynonyms.cs │ │ ├── NlpIngredientSynonyms.cs │ │ ├── NlpPrepNotes.cs │ │ ├── NlpUnitSynonyms.cs │ │ ├── QueuedRecipes.cs │ │ ├── RecipeData.cs │ │ ├── RecipeIngredients.cs │ │ ├── RecipeMetadata.cs │ │ ├── RecipeRatings.cs │ │ ├── Recipes.cs │ │ ├── ShoppingListItems.cs │ │ └── ShoppingLists.cs │ ├── DataStore.cs │ ├── IProvisionSource.cs │ ├── IProvisionTarget.cs │ └── IProvisioner.cs ├── Recipes │ ├── Enums.cs │ ├── ReadRecipeOptions.cs │ ├── Recipe.cs │ ├── RecipeBrief.cs │ ├── RecipeQuery.cs │ ├── RecipeResult.cs │ ├── RecipeTag.cs │ ├── RecipeTags.cs │ └── SearchResults.cs ├── ShoppingLists │ ├── Enums.cs │ ├── GetShoppingListOptions.cs │ ├── IShoppingListSource.cs │ ├── ShoppingList.cs │ ├── ShoppingListItem.cs │ ├── ShoppingListModification.cs │ ├── ShoppingListResult.cs │ └── ShoppingListUpdateCommand.cs ├── Unit.cs ├── UnitConverter.cs ├── Weight.cs └── packages.config ├── DB ├── DB.csproj ├── DatabaseAdapter.cs ├── DatabaseAdapterBuilder.cs ├── DatabaseExporter.cs ├── DatabaseImporter.cs ├── EnumMapper.cs ├── Models │ ├── Favorites.cs │ ├── IngredientForms.cs │ ├── IngredientMetadata.cs │ ├── Ingredients.cs │ ├── Menus.cs │ ├── NlpAnomalousIngredients.cs │ ├── NlpDefaultPairings.cs │ ├── NlpFormSynonyms.cs │ ├── NlpIngredientSynonyms.cs │ ├── NlpPrepNotes.cs │ ├── NlpUnitSynonyms.cs │ ├── QueuedRecipes.cs │ ├── RecipeIngredients.cs │ ├── RecipeMetadata.cs │ ├── RecipeRatings.cs │ ├── Recipes.cs │ ├── ShoppingListItems.cs │ └── ShoppingLists.cs ├── NHSearch.cs ├── NLP │ ├── AnomalyLoader.cs │ ├── FormLoader.cs │ ├── IngredientGraphTransformer.cs │ ├── IngredientLoader.cs │ ├── PrepLoader.cs │ └── UnitLoader.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── KitchenPC.sln ├── SampleData └── KPCData.xml ├── UnitTests ├── Categorization.cs ├── Mock │ ├── Forms.cs │ ├── Ingredients.cs │ ├── MockContext.cs │ ├── MockImpossibleFilterUserProfile.cs │ ├── MockImpossiblePantryUserProfile.cs │ ├── MockModelerDBLoader.cs │ ├── MockNoRatingsUserProfile.cs │ ├── MockNormalUserProfile.cs │ └── Recipes.cs ├── Modeler.cs ├── ModelerData.xml ├── NLP.cs ├── Properties │ └── AssemblyInfo.cs ├── Tags.cs ├── TestFormLoader.cs ├── TestIngredientLoader.cs ├── TestPrepLoader.cs ├── TestUnitLoader.cs ├── UnitConverter.cs ├── UnitTests.csproj ├── Units.cs └── packages.config ├── build.xml └── packages ├── FluentNHibernate.2.0.3.0 ├── FluentNHibernate.2.0.3.0.nupkg ├── FluentNHibernate.2.0.3.0.nuspec └── lib │ └── net40 │ ├── FluentNHibernate.XML │ ├── FluentNHibernate.dll │ └── FluentNHibernate.pdb ├── Iesi.Collections.4.0.1.4000 ├── Iesi.Collections.4.0.1.4000.nupkg ├── Iesi.Collections.4.0.1.4000.nuspec └── lib │ └── net40 │ ├── Iesi.Collections.dll │ └── Iesi.Collections.xml ├── NHibernate.4.0.4.4000 ├── ConfigurationTemplates │ ├── FireBird.cfg.xml │ ├── MSSQL.cfg.xml │ ├── MySql.cfg.xml │ ├── Oracle.cfg.xml │ ├── PostgreSQL.cfg.xml │ ├── SQLite.cfg.xml │ ├── SybaseASE.cfg.xml │ └── SybaseSQLAnywhere.cfg.xml ├── NHibernate.4.0.4.4000.nupkg ├── NHibernate.4.0.4.4000.nuspec ├── NHibernate.license.txt ├── NHibernate.readme.html ├── NHibernate.releasenotes.txt ├── lib │ └── net40 │ │ ├── NHibernate.dll │ │ └── NHibernate.xml ├── nhibernate-configuration.xsd └── nhibernate-mapping.xsd ├── NUnit.3.4.1 ├── CHANGES.txt ├── LICENSE.txt ├── NOTICES.txt ├── NUnit.3.4.1.nupkg ├── NUnit.3.4.1.nuspec └── lib │ ├── dotnet │ ├── nunit.framework.dll │ └── nunit.framework.xml │ ├── net20 │ ├── NUnit.System.Linq.dll │ ├── nunit.framework.dll │ └── nunit.framework.xml │ ├── net35 │ ├── nunit.framework.dll │ └── nunit.framework.xml │ ├── net40 │ ├── nunit.framework.dll │ └── nunit.framework.xml │ ├── net45 │ ├── nunit.framework.dll │ └── nunit.framework.xml │ └── portable-net45+win8+wp8+wpa81+Xamarin.Mac+MonoAndroid10+MonoTouch10+Xamarin.iOS10 │ ├── nunit.framework.dll │ └── nunit.framework.xml ├── Npgsql.3.1.7 ├── Npgsql.3.1.7.nupkg ├── Npgsql.3.1.7.nuspec └── lib │ ├── net45 │ ├── Npgsql.dll │ └── Npgsql.xml │ ├── net451 │ ├── Npgsql.dll │ └── Npgsql.xml │ └── netstandard1.3 │ ├── Npgsql.dll │ └── Npgsql.xml ├── log4net.2.0.5 ├── lib │ ├── net10-full │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net11-full │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net20-full │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net35-client │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net35-full │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net40-client │ │ ├── log4net.dll │ │ └── log4net.xml │ ├── net40-full │ │ ├── log4net.dll │ │ └── log4net.xml │ └── net45-full │ │ ├── log4net.dll │ │ └── log4net.xml ├── log4net.2.0.5.nupkg └── log4net.2.0.5.nuspec └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | src/Core/bin/ 2 | src/Core/obj/ 3 | src/DB/bin/ 4 | src/DB/obj/ 5 | src/UnitTests/bin/ 6 | src/UnitTests/obj/ 7 | *.suo -------------------------------------------------------------------------------- /BuildShell.ps1: -------------------------------------------------------------------------------- 1 | # KitchenPC Dev Shell setup 2 | 3 | # To use, add the following programs to your system path: 4 | # msbuild.exe (Provided with the .NET Framework) 5 | # nunit-console.exe (Available at http://nunit.org/) 6 | 7 | # Optionally, add the following shortcut to your quick launch or start menu: 8 | # %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -noexit -file "c:\KitchenPC\BuildShell.ps1" "C:\KitchenPC" 9 | # You can substitute C:\KitchenPC with the path to your KitchenPC enlistment. 10 | 11 | param([String]$enlistment="C:\KitchenPC\") 12 | Write-Host "Initializing KitchenPC Dev Shell, Please Wait..." -NoNewLine 13 | $host.ui.RawUI.WindowTitle = "KitchenPC Dev Shell" 14 | 15 | New-PSDrive -name kpc -PSProvider FileSystem -root $enlistment >$null 16 | Set-Alias vs "kpc:\src\KitchenPC.sln" 17 | 18 | function cd.. 19 | { 20 | Set-Location .. 21 | } 22 | 23 | function cd\ 24 | { 25 | Set-Location \ 26 | } 27 | 28 | function Guid 29 | { 30 | Write-Host ([System.Guid]::NewGuid().ToString()) 31 | } 32 | 33 | function Test 34 | { 35 | $testpath = Convert-Path('kpc:\src\UnitTests\bin\Debug\') 36 | nunit-console.exe ($testpath + "KitchenPC.UnitTests.dll") 37 | } 38 | 39 | function Build 40 | { 41 | if ($args.Count -gt 0) 42 | { 43 | switch ($args[0].ToUpper()) 44 | { 45 | "DEBUG" { msbuild .\build.xml /t:Build /p:Configuration=Debug /verbosity:minimal } 46 | "RELEASE" { msbuild .\build.xml /t:Build /p:Configuration=Release /verbosity:minimal } 47 | } 48 | } 49 | else 50 | { 51 | msbuild .\build.xml /t:Build /p:Configuration=Debug /verbosity:minimal 52 | } 53 | } 54 | 55 | function Clean 56 | { 57 | msbuild .\build.xml /t:Clean 58 | } 59 | 60 | #Set default location 61 | Set-Location kpc:\src\ 62 | Write-Host " Done.`n`n" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 KitchenPC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is KitchenPC? 2 | ==== 3 | 4 | KitchenPC is a free, open-source framework written in C# for working with recipes, shopping lists, and menus. It provides a standardized data model for representing normalized ingredient and recipe information, and allows ingredient usage to be aggregated across recipes automatically. The core KitchenPC framework includes: 5 | 6 | 1. Base classes for describing and working with core recipe-related concepts. 7 | 2. A **recipe modeling engine** capable of building sets of recipes that efficiently use a set of ingredients and amounts. 8 | 3. A **natural language parser** which can convert human input ("a dozen eggs") to a normalized ingredient usage structure (whole eggs: 12) 9 | 4. A **categorization engine** which can take recipe objects and catagorize them as breakfast, lunch, dinner or dessert. This engine can also derive nutrional information based on USDA data, a taste profile (sweet, savory, spicy, mild) based on ingredients and amounts used, dietary flags (vegetarian, gluten-free, low-calorie, etc) and other aspects of the recipe. 10 | 5. An extensible framework to define how data is loaded and saved to a persistence mechanism, such as a SQL database or full-text search engine. 11 | 12 | How To Get Started 13 | ==== 14 | 15 | Getting started is simple, and data can be loaded locally from an XML file for testing. Sample data is included with the source, which includes a few dozen recipes, along with sample menus and shopping lists. 16 | 17 | The best way to get up and running is to read the blog post titled [Getting Started with KitchenPC](http://blog.kitchenpc.com/2014/02/10/getting-started-with-kitchenpc/) which includes an introduction to core concepts as well as several samples. 18 | 19 | 1. [Getting Started](http://blog.kitchenpc.com/2014/02/10/getting-started-with-kitchenpc/) 20 | 2. [Provisioning a Database](http://blog.kitchenpc.com/2014/02/11/kitchenpc-database-provisioning-101/) 21 | 3. [Logging](http://blog.kitchenpc.com/2014/02/13/kitchenpc-logging-101/) 22 | 4. [Creating a Recipe](http://blog.kitchenpc.com/2014/02/14/lets-make-a-recipe/) 23 | -------------------------------------------------------------------------------- /src/Core/AuthIdentity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Security.Cryptography; 4 | using System.Security.Principal; 5 | using System.Text; 6 | 7 | namespace KitchenPC 8 | { 9 | /// Represents a user identity within a KitchenPC context. This identity can be stored locally or within the KitchenPC network. 10 | public class AuthIdentity : IIdentity 11 | { 12 | public Guid UserId { get; private set; } 13 | public string Name { get; private set; } 14 | 15 | public AuthIdentity() 16 | { 17 | } 18 | 19 | public AuthIdentity(Guid id, string name) 20 | { 21 | UserId = id; 22 | Name = name; 23 | } 24 | 25 | public string AuthenticationType 26 | { 27 | get 28 | { 29 | return "KPCAuth"; 30 | } 31 | } 32 | 33 | public bool IsAuthenticated 34 | { 35 | get 36 | { 37 | return UserId != Guid.Empty; 38 | } 39 | } 40 | 41 | public static string CreateHash(string value) 42 | { 43 | var hasher = MD5.Create(); 44 | var bytes = hasher.ComputeHash(Encoding.Unicode.GetBytes(value)); 45 | return Convert.ToBase64String(bytes); 46 | } 47 | 48 | public override string ToString() 49 | { 50 | if (IsAuthenticated) 51 | { 52 | return String.Format("{0} ({1})", Name, UserId.ToString()); 53 | } 54 | else 55 | { 56 | return ""; 57 | } 58 | } 59 | 60 | public static Byte[] Serialize(AuthIdentity identity) 61 | { 62 | var g = identity.UserId.ToByteArray(); 63 | var u = Encoding.UTF8.GetBytes(identity.Name); 64 | 65 | return g.Concat(u).ToArray(); 66 | } 67 | 68 | public static AuthIdentity Deserialize(Byte[] bytes) 69 | { 70 | if (bytes.Length < 17) 71 | throw new ArgumentException("AuthIdentity must be at least 17 bytes."); 72 | 73 | var g = new byte[16]; 74 | var u = new byte[bytes.Length - 16]; 75 | 76 | Buffer.BlockCopy(bytes, 0, g, 0, 16); 77 | Buffer.BlockCopy(bytes, 16, u, 0, u.Length); 78 | 79 | return new AuthIdentity( 80 | new Guid(g), 81 | Encoding.UTF8.GetString(u)); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/Core/Categorization/AnalyzerResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Categorization 4 | { 5 | public class AnalyzerResult 6 | { 7 | public Category FirstPlace { get; private set; } 8 | public Category SecondPlace { get; private set; } 9 | 10 | public AnalyzerResult(Category first, Category second) 11 | { 12 | FirstPlace = first; 13 | SecondPlace = second; 14 | } 15 | 16 | public override string ToString() 17 | { 18 | return SecondPlace == Category.None ? FirstPlace.ToString() 19 | : String.Format("{0}/{1}", FirstPlace, SecondPlace); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Core/Categorization/CategorizationResult.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | public class CategorizationResult 4 | { 5 | public bool Diet_GlutenFree; 6 | public bool Diet_NoAnimals; 7 | public bool Diet_NoMeat; 8 | public bool Diet_NoPork; 9 | public bool Diet_NoRedMeat; 10 | public bool Meal_Breakfast; 11 | public bool Meal_Dessert; 12 | public bool Meal_Dinner; 13 | public bool Meal_Lunch; 14 | public bool Nutrition_LowCalorie; 15 | public bool Nutrition_LowCarb; 16 | public bool Nutrition_LowFat; 17 | public bool Nutrition_LowSodium; 18 | public bool Nutrition_LowSugar; 19 | public short Nutrition_TotalCalories; 20 | public short Nutrition_TotalCarbs; 21 | public short Nutrition_TotalFat; 22 | public short Nutrition_TotalSodium; 23 | public short Nutrition_TotalSugar; 24 | public bool Skill_Easy; 25 | public bool Skill_Quick; 26 | public bool Skill_Common; 27 | public byte Taste_MildToSpicy; 28 | public byte Taste_SavoryToSweet; 29 | public float Commonality; 30 | 31 | public bool USDAMatch; 32 | } 33 | } -------------------------------------------------------------------------------- /src/Core/Categorization/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | public enum Category 4 | { 5 | None, 6 | Breakfast, 7 | Lunch, 8 | Dinner, 9 | Dessert 10 | }; 11 | } -------------------------------------------------------------------------------- /src/Core/Categorization/IDBLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.Categorization 4 | { 5 | public interface IDBLoader 6 | { 7 | IEnumerable LoadCommonIngredients(); 8 | IEnumerable LoadTrainingData(); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/Categorization/IIngredientCommonality.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Categorization 4 | { 5 | public interface IIngredientCommonality 6 | { 7 | Guid IngredientId { get; } 8 | Single Commonality { get; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/Categorization/IRecipeClassification.cs: -------------------------------------------------------------------------------- 1 | using KitchenPC.Recipes; 2 | 3 | namespace KitchenPC.Categorization 4 | { 5 | public interface IRecipeClassification 6 | { 7 | Recipe Recipe { get; } 8 | 9 | bool IsBreakfast { get; } 10 | bool IsLunch { get; } 11 | bool IsDinner { get; } 12 | bool IsDessert { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/Categorization/IToken.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | public interface IToken 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /src/Core/Categorization/IngredientToken.cs: -------------------------------------------------------------------------------- 1 | using KitchenPC.Ingredients; 2 | 3 | namespace KitchenPC.Categorization 4 | { 5 | internal class IngredientToken : IToken 6 | { 7 | readonly Ingredient ing; 8 | 9 | public IngredientToken(Ingredient ing) 10 | { 11 | this.ing = ing; 12 | } 13 | 14 | public override bool Equals(object obj) 15 | { 16 | var t1 = obj as IngredientToken; 17 | return (t1 != null && t1.ing.Id.Equals(ing.Id)); 18 | } 19 | 20 | public override int GetHashCode() 21 | { 22 | return ing.Id.GetHashCode(); 23 | } 24 | 25 | public override string ToString() 26 | { 27 | return "[ING] - " + ing; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Core/Categorization/Ranking.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | internal class Ranking 4 | { 5 | public float Score { get; set; } 6 | public Category Type { get; private set; } 7 | 8 | public Ranking(Category type) 9 | { 10 | this.Type = type; 11 | this.Score = 0f; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/Categorization/RecipeIndex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.Categorization 6 | { 7 | public class RecipeIndex 8 | { 9 | readonly Dictionary index = new Dictionary(); 10 | 11 | public int EntryCount 12 | { 13 | get 14 | { 15 | return index.Values.Sum(); 16 | } 17 | } 18 | 19 | public int GetTokenCount(IToken token) 20 | { 21 | return index.ContainsKey(token) ? index[token] : 0; 22 | } 23 | 24 | public void Add(Recipe recipe) 25 | { 26 | var tokens = Tokenizer.Tokenize(recipe); 27 | foreach (var token in tokens) 28 | { 29 | if (index.ContainsKey(token)) 30 | { 31 | index[token]++; 32 | } 33 | else 34 | { 35 | index.Add(token, 1); 36 | } 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Core/Categorization/TextToken.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | internal class TextToken : IToken 4 | { 5 | readonly string text; 6 | 7 | public TextToken(string text) 8 | { 9 | this.text = text.Trim().ToLower(); 10 | } 11 | 12 | public override bool Equals(object obj) 13 | { 14 | var t1 = obj as TextToken; 15 | return (t1 != null && t1.text.Equals(text)); 16 | } 17 | 18 | public override int GetHashCode() 19 | { 20 | return text.GetHashCode(); 21 | } 22 | 23 | public override string ToString() 24 | { 25 | return text; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Core/Categorization/TimeToken.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Categorization 2 | { 3 | internal class TimeToken : IToken 4 | { 5 | enum Classification 6 | { 7 | Quick, 8 | Medium, 9 | Long, 10 | SuperLong 11 | }; 12 | 13 | readonly Classification classification; 14 | 15 | public TimeToken(int minutes) 16 | { 17 | if (minutes < 10) classification = Classification.Quick; 18 | else if (minutes < 30) classification = Classification.Medium; 19 | else if (minutes <= 60) classification = Classification.Long; 20 | else classification = Classification.SuperLong; 21 | } 22 | 23 | public override bool Equals(object obj) 24 | { 25 | var t1 = obj as TimeToken; 26 | return (t1 != null && t1.classification.Equals(classification)); 27 | } 28 | 29 | public override int GetHashCode() 30 | { 31 | return classification.GetHashCode(); 32 | } 33 | 34 | public override string ToString() 35 | { 36 | return classification.ToString(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Core/Categorization/Tokenizer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | using KitchenPC.Recipes; 5 | 6 | namespace KitchenPC.Categorization 7 | { 8 | //Takes a Recipe object and returns an enumeration of Token objects 9 | public static class Tokenizer 10 | { 11 | static readonly Regex valid = new Regex(@"[a-z]", RegexOptions.IgnoreCase); //All tokens have to have at least one letter in them 12 | 13 | static IEnumerable ParseText(string text) 14 | { 15 | var parts = Regex.Split(text, @"[^a-z0-9\'\$\-]", RegexOptions.IgnoreCase); 16 | return (from p in parts where valid.IsMatch(p) select new TextToken(p) as IToken); 17 | } 18 | 19 | public static IEnumerable Tokenize(Recipe recipe) 20 | { 21 | var tokens = new List(); 22 | tokens.AddRange(ParseText(recipe.Title ?? "")); 23 | tokens.AddRange(ParseText(recipe.Description ?? "")); 24 | //tokens.AddRange(ParseText(recipe.Method ?? "")); 25 | //tokens.Add(new TimeToken(recipe.CookTime.GetValueOrDefault() + recipe.PrepTime.GetValueOrDefault())); 26 | tokens.AddRange(from i in recipe.Ingredients.NeverNull() select new IngredientToken(i.Ingredient) as IToken); 27 | 28 | return tokens; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/Context/AlphaTree.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Context 2 | { 3 | public class AlphaTree 4 | { 5 | public Node Head; 6 | 7 | public AlphaTree() 8 | { 9 | Head = new Node(); 10 | } 11 | 12 | public class Node 13 | { 14 | readonly Node[] nodes; 15 | public ConnectorVertex connections; 16 | 17 | public Node() 18 | { 19 | nodes = new Node[26]; 20 | } 21 | 22 | public Node AddLink(char c) 23 | { 24 | var index = c - 97; 25 | return (nodes[index] = new Node()); 26 | } 27 | 28 | public bool HasLink(char c) 29 | { 30 | var index = c - 97; 31 | return (nodes[index] != null); 32 | } 33 | 34 | public Node GetLink(char c) 35 | { 36 | var index = c - 97; 37 | return nodes[index]; 38 | } 39 | 40 | public void AddConnection(IngredientNode node) 41 | { 42 | if (connections == null) 43 | { 44 | connections = new ConnectorVertex(); 45 | } 46 | else 47 | { 48 | if (connections.HasConnection(node)) 49 | return; 50 | } 51 | 52 | connections.AddConnection(node); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Core/Context/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public class Configuration : IConfiguration where T : IKPCContext 6 | { 7 | readonly ConfigurationBuilder builder; 8 | 9 | public T Context { get; set; } 10 | 11 | public static ConfigurationBuilder Build 12 | { 13 | get 14 | { 15 | return new Configuration().builder; 16 | } 17 | } 18 | 19 | public static IConfiguration Xml 20 | { 21 | get 22 | { 23 | // TODO: Read local XML configuration and return ConfigurationBuilder 24 | throw new NotImplementedException(); 25 | } 26 | } 27 | 28 | Configuration() 29 | { 30 | builder = new ConfigurationBuilder(this); 31 | } 32 | 33 | public T InitializeContext() 34 | { 35 | Context.Initialize(); 36 | return Context; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Core/Context/ConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Context 2 | { 3 | /// Fluent interface to create configuration objects 4 | public class ConfigurationBuilder : IConfigurationBuilder> where T : IKPCContext 5 | { 6 | readonly IConfiguration configuration; 7 | 8 | public ConfigurationBuilder(IConfiguration config) 9 | { 10 | configuration = config; 11 | } 12 | 13 | public ConfigurationBuilder Context(IConfigurationBuilder context) 14 | { 15 | configuration.Context = context.Create(); 16 | return this; 17 | } 18 | 19 | public IConfiguration Create() 20 | { 21 | return configuration; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/Context/ConnectorVertex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace KitchenPC.Context 5 | { 6 | public class ConnectorVertex 7 | { 8 | readonly List connections; 9 | 10 | public ConnectorVertex() 11 | { 12 | connections = new List(); 13 | } 14 | 15 | public IEnumerable Connections 16 | { 17 | get 18 | { 19 | return connections.AsEnumerable(); 20 | } 21 | } 22 | 23 | public void AddConnection(IngredientNode node) 24 | { 25 | connections.Add(node); 26 | } 27 | 28 | public bool HasConnection(IngredientNode node) 29 | { 30 | return connections.Contains(node); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Core/Context/DBContextBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public class DBContextBuilder : IConfigurationBuilder 6 | { 7 | readonly DBContext context; 8 | 9 | public DBContextBuilder(DBContext context) 10 | { 11 | this.context = context; 12 | } 13 | 14 | public DBContextBuilder Adapter(IConfigurationBuilder adapter) where T : IDBAdapter 15 | { 16 | context.Adapter = adapter.Create(); 17 | return this; 18 | } 19 | 20 | public DBContextBuilder Identity(Func getIdentity) 21 | { 22 | context.GetIdentity = getIdentity; 23 | return this; 24 | } 25 | 26 | public DBContext Create() 27 | { 28 | return context; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/Context/DBModelerLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using KitchenPC.Modeler; 3 | 4 | namespace KitchenPC.Context 5 | { 6 | public class DBModelerLoader : IModelerLoader 7 | { 8 | readonly IDBAdapter adapter; 9 | IEnumerable recipedata; 10 | IEnumerable ingredientdata; 11 | IEnumerable ratingdata; 12 | 13 | public DBModelerLoader(IDBAdapter adapter) 14 | { 15 | this.adapter = adapter; 16 | } 17 | 18 | public IEnumerable LoadRecipeGraph() 19 | { 20 | if (recipedata == null) 21 | recipedata = adapter.LoadRecipeGraph(); 22 | 23 | return recipedata; 24 | } 25 | 26 | public IEnumerable LoadIngredientGraph() 27 | { 28 | if (ingredientdata == null) 29 | ingredientdata = adapter.LoadIngredientGraph(); 30 | 31 | return ingredientdata; 32 | } 33 | 34 | public IEnumerable LoadRatingGraph() 35 | { 36 | if (ratingdata == null) 37 | ratingdata = adapter.LoadRatingGraph(); 38 | 39 | return ratingdata; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/Context/IConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Context 2 | { 3 | /// 4 | /// Implements an object which holds the configuration for a certain type of context. 5 | /// 6 | /// A type which implements IKPCContext 7 | public interface IConfiguration where T : IKPCContext 8 | { 9 | T Context { get; set; } 10 | 11 | T InitializeContext(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Core/Context/IConfigurationBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Context 2 | { 3 | /// 4 | /// Implements an object which can build an IConfiguration for a certain type of context. 5 | /// 6 | /// A KitchenPC context type this builder will create a configuration for. 7 | public interface IConfigurationBuilder 8 | { 9 | T Create(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Context/ISearchProvider.cs: -------------------------------------------------------------------------------- 1 | using KitchenPC.Recipes; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | /// 6 | /// Provides a KitchenPC database adapter with a way to search for recipes based on a query. 7 | /// 8 | public interface ISearchProvider 9 | { 10 | SearchResults Search(AuthIdentity identity, RecipeQuery query); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Context/IngredientNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public class IngredientNode 6 | { 7 | public Guid Id; 8 | public string IngredientName; 9 | public int Popularity; 10 | 11 | public IngredientNode(Guid id, string name, int popularity) 12 | { 13 | Id = id; 14 | IngredientName = name; 15 | Popularity = popularity; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Core/Context/IngredientSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public class IngredientSource 6 | { 7 | public Guid Id { get; private set; } 8 | public String DisplayName { get; private set; } 9 | 10 | public IngredientSource(Guid id, String displayname) 11 | { 12 | this.Id = id; 13 | this.DisplayName = displayname; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Core/Context/KPCContext.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public static class KPCContext 6 | { 7 | public static IKPCContext Current { get; private set; } 8 | public static ILog Log = LogManager.GetLogger(typeof (KPCContext)); 9 | 10 | /// 11 | /// Initializes a given KitchenPC context. After calling this method, KPCContext.Current will refer to that context. 12 | /// 13 | /// An instance of a KitchenPC context. 14 | public static void Initialize(IKPCContext context) 15 | { 16 | Log.InfoFormat("Initializing global KitchenPC Context of type {0}", context.GetType().Name); 17 | 18 | context.Initialize(); 19 | Current = context; 20 | } 21 | 22 | /// 23 | /// Initializes a given KitchenPC context. After calling this method, KPCContext.Current will refer to that context. 24 | /// 25 | /// A type of KitchenPC context to initialize. 26 | /// A configuration able to build a context of the specified type. A configuration builder can be obtained using Configuration<T>.Build 27 | public static void Initialize(IConfiguration configuration) where T : IKPCContext 28 | { 29 | Initialize(configuration.Context); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Core/Context/StaticContextBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Context 4 | { 5 | public class StaticContextBuilder : IConfigurationBuilder 6 | { 7 | readonly StaticContext context; 8 | 9 | public StaticContextBuilder(StaticContext context) 10 | { 11 | this.context = context; 12 | } 13 | 14 | /// A path on the file system that contains a KitchenPC data file. 15 | public StaticContextBuilder DataDirectory(string path) 16 | { 17 | context.DataDirectory = path; 18 | return this; 19 | } 20 | 21 | /// Configures context to compress the store file on disk to save space. 22 | public StaticContextBuilder CompressedStore 23 | { 24 | get 25 | { 26 | context.CompressedStore = true; 27 | return this; 28 | } 29 | } 30 | 31 | public StaticContextBuilder Identity(Func getIdentity) 32 | { 33 | context.GetIdentity = getIdentity; 34 | return this; 35 | } 36 | 37 | public StaticContext Create() 38 | { 39 | return context; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/Context/StaticFormLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using KitchenPC.Data; 4 | using KitchenPC.Ingredients; 5 | using KitchenPC.NLP; 6 | 7 | namespace KitchenPC.Context 8 | { 9 | public class StaticFormLoader : ISynonymLoader 10 | { 11 | readonly DataStore store; 12 | 13 | public StaticFormLoader(DataStore store) 14 | { 15 | this.store = store; 16 | } 17 | 18 | public IEnumerable LoadSynonyms() 19 | { 20 | var formSyn = store.NlpFormSynonyms 21 | .OrderBy(p => p.Name) 22 | .Select(s => s.Name) 23 | .Distinct() 24 | .ToList(); 25 | 26 | return new List(formSyn.Select(s => new FormNode(s))); 27 | } 28 | 29 | public Pairings LoadFormPairings() 30 | { 31 | var forms = store.GetIndexedIngredientForms(); 32 | var formSyn = store.NlpFormSynonyms; 33 | var pairings = new Pairings(); 34 | 35 | foreach (var syn in formSyn) 36 | { 37 | var f = forms[syn.FormId]; 38 | 39 | var name = syn.Name; 40 | var ing = syn.IngredientId; 41 | var form = f.IngredientFormId; 42 | var convType = f.UnitType; 43 | var displayName = f.FormDisplayName; 44 | var unitName = f.UnitName; 45 | int convMultiplier = f.ConvMultiplier; 46 | var formAmt = f.FormAmount; 47 | var formUnit = f.FormUnit; 48 | var amount = new Amount(formAmt, formUnit); 49 | 50 | pairings.Add( 51 | new NameIngredientPair(name, ing), 52 | new IngredientForm(form, ing, convType, displayName, unitName, convMultiplier, amount)); 53 | } 54 | 55 | return pairings; 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Core/Context/StaticPrepLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using KitchenPC.Data; 5 | using KitchenPC.NLP; 6 | 7 | namespace KitchenPC.Context 8 | { 9 | public class StaticPrepLoader : ISynonymLoader 10 | { 11 | readonly DataStore store; 12 | 13 | public StaticPrepLoader(DataStore store) 14 | { 15 | this.store = store; 16 | } 17 | 18 | public IEnumerable LoadSynonyms() 19 | { 20 | var forms = store.NlpFormSynonyms.Select(p => p.Name); 21 | var preps = store.NlpPrepNotes.Select(p => p.Name); 22 | 23 | var ret = forms 24 | .Concat(preps) 25 | .Distinct() 26 | .Select(p => new PrepNode(p)) 27 | .ToList(); 28 | 29 | return ret; 30 | } 31 | 32 | public Pairings LoadFormPairings() 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/Core/Context/StaticUnitLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using KitchenPC.Data; 4 | using KitchenPC.Ingredients; 5 | using KitchenPC.NLP; 6 | 7 | namespace KitchenPC.Context 8 | { 9 | public class StaticUnitLoader : ISynonymLoader 10 | { 11 | readonly DataStore store; 12 | 13 | public StaticUnitLoader(DataStore store) 14 | { 15 | this.store = store; 16 | } 17 | 18 | public IEnumerable LoadSynonyms() 19 | { 20 | var unitSyn = store.NlpUnitSynonyms 21 | .OrderBy(p => p.Name) 22 | .Select(p => p.Name) 23 | .Distinct() 24 | .ToList(); 25 | 26 | return new List(unitSyn.Select(s => new CustomUnitNode(s))); 27 | } 28 | 29 | public Pairings LoadFormPairings() 30 | { 31 | var forms = store.GetIndexedIngredientForms(); 32 | var unitSyn = store.NlpUnitSynonyms; 33 | var pairings = new Pairings(); 34 | 35 | foreach (var syn in unitSyn) 36 | { 37 | var form = forms[syn.FormId]; 38 | 39 | pairings.Add(new NameIngredientPair( 40 | syn.Name.Trim(), 41 | syn.IngredientId), 42 | new IngredientForm( 43 | form.IngredientFormId, 44 | form.IngredientId, 45 | form.UnitType, 46 | form.FormDisplayName, 47 | form.UnitName, 48 | form.ConvMultiplier, 49 | new Amount(form.FormAmount, form.FormUnit))); 50 | } 51 | 52 | return pairings; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Core/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC 2 | { 3 | public enum UnitType 4 | { 5 | Unit = 0, 6 | Volume = 1, 7 | Weight = 2 8 | } 9 | 10 | public enum Units 11 | { 12 | //Individual items 13 | Unit = 0, 14 | 15 | //Volume 16 | Teaspoon = 1, 17 | Tablespoon = 2, 18 | FluidOunce = 3, 19 | Cup = 4, 20 | Pint = 5, 21 | Quart = 6, 22 | Gallon = 7, 23 | 24 | //Weight 25 | Gram = 8, 26 | Ounce = 9, 27 | Pound = 10, 28 | } 29 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/Ingredient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Ingredients 4 | { 5 | public class Ingredient 6 | { 7 | public Guid Id; 8 | public String Name; 9 | public UnitType ConversionType; 10 | public String UnitName; 11 | public Weight UnitWeight; 12 | 13 | public IngredientMetadata Metadata; 14 | 15 | public static Ingredient FromId(Guid ingredientId) 16 | { 17 | return new Ingredient 18 | { 19 | Id = ingredientId 20 | }; 21 | } 22 | 23 | public Ingredient(Guid id, String name) 24 | { 25 | Id = id; 26 | Name = name; 27 | Metadata = new IngredientMetadata(); 28 | } 29 | 30 | public Ingredient(Guid id, String name, IngredientMetadata metadata) 31 | { 32 | Id = id; 33 | Name = name; 34 | Metadata = metadata; 35 | } 36 | 37 | public Ingredient() : this(Guid.Empty, String.Empty) 38 | { 39 | } 40 | 41 | public override string ToString() 42 | { 43 | return Name; 44 | } 45 | 46 | public override bool Equals(object obj) 47 | { 48 | var i = obj as Ingredient; 49 | return (i != null && this.Id == i.Id); 50 | } 51 | 52 | public override int GetHashCode() 53 | { 54 | return Id.GetHashCode(); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientAggregation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.ShoppingLists; 3 | 4 | namespace KitchenPC.Ingredients 5 | { 6 | public class IngredientAggregation : IShoppingListSource 7 | { 8 | public Ingredient Ingredient; 9 | public Amount Amount; 10 | 11 | public IngredientAggregation(Ingredient ingredient) 12 | { 13 | this.Ingredient = ingredient; 14 | 15 | if (ingredient != null) 16 | { 17 | this.Amount = new Amount(); 18 | this.Amount.Unit = Unit.GetDefaultUnitType(ingredient.ConversionType); 19 | } 20 | } 21 | 22 | public IngredientAggregation(Ingredient ingredient, Amount baseAmount) 23 | { 24 | this.Ingredient = ingredient; 25 | this.Amount = baseAmount; 26 | } 27 | 28 | public override string ToString() 29 | { 30 | if (Ingredient != null && Amount != null) 31 | return String.Format("{0}: {1}", Ingredient.Name, Amount); 32 | 33 | if (Ingredient != null) 34 | return Ingredient.Name; 35 | 36 | return String.Empty; 37 | } 38 | 39 | public virtual IngredientAggregation AddUsage(IngredientUsage ingredient) 40 | { 41 | if (ingredient.Ingredient.Id != this.Ingredient.Id) 42 | throw new ArgumentException("Can only call IngredientAggregation::AddUsage() on original ingredient."); 43 | 44 | //Calculate new total 45 | if (this.Amount.Unit == ingredient.Amount.Unit || UnitConverter.CanConvert(this.Amount.Unit, ingredient.Amount.Unit)) //Just add 46 | { 47 | this.Amount += ingredient.Amount; 48 | } 49 | else //Find a conversion path between Ingredient and Form 50 | { 51 | var amount = FormConversion.GetNativeAmountForUsage(this.Ingredient, ingredient); 52 | this.Amount += amount; 53 | } 54 | 55 | return this; // Allows AddUsage calls to be chained together 56 | } 57 | 58 | public virtual ShoppingListItem GetItem() 59 | { 60 | return new ShoppingListItem(Ingredient) 61 | { 62 | Amount = Amount 63 | }; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Ingredients 4 | { 5 | public class IngredientForm 6 | { 7 | public Guid FormId; 8 | public Guid IngredientId; 9 | public Units FormUnitType; 10 | public string FormDisplayName; 11 | public string FormUnitName; 12 | public int ConversionMultiplier; 13 | public Amount FormAmount; 14 | 15 | public static IngredientForm FromId(Guid id) 16 | { 17 | return new IngredientForm 18 | { 19 | FormId = id 20 | }; 21 | } 22 | 23 | public IngredientForm() 24 | { 25 | } 26 | 27 | public IngredientForm(Guid formid, Guid ingredientid, Units unittype, string displayname, string unitname, int convmultiplier, Amount amount) 28 | { 29 | FormId = formid; 30 | IngredientId = ingredientid; 31 | FormUnitType = unittype; 32 | FormDisplayName = displayname; 33 | FormUnitName = unitname; 34 | ConversionMultiplier = convmultiplier; 35 | FormAmount = amount; 36 | } 37 | 38 | public override string ToString() 39 | { 40 | return FormId.ToString(); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientFormsCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.Ingredients 4 | { 5 | public class IngredientFormsCollection 6 | { 7 | readonly List _forms; 8 | 9 | public IngredientForm[] Forms 10 | { 11 | get 12 | { 13 | return _forms.ToArray(); 14 | } 15 | 16 | set 17 | { 18 | _forms.Clear(); 19 | foreach (var form in value) 20 | _forms.Add(form); 21 | } 22 | } 23 | 24 | public IngredientFormsCollection() 25 | { 26 | _forms = new List(); 27 | } 28 | 29 | public IngredientFormsCollection(IEnumerable forms) 30 | { 31 | _forms = new List(forms); 32 | } 33 | 34 | public void AddForm(IngredientForm form) 35 | { 36 | _forms.Add(form); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Ingredients 2 | { 3 | public class IngredientMetadata 4 | { 5 | public bool? HasGluten; 6 | public bool? HasMeat; 7 | public bool? HasRedMeat; 8 | public bool? HasPork; 9 | public bool? HasAnimal; 10 | public short Spicy; 11 | public short Sweet; 12 | public float? FatPerUnit; 13 | public float? SugarPerUnit; 14 | public float? CaloriesPerUnit; 15 | public float? SodiumPerUnit; 16 | public float? CarbsPerUnit; 17 | 18 | public IngredientMetadata() 19 | { 20 | } 21 | 22 | public IngredientMetadata(bool? hasgluten, bool? hasmeat, bool? hasredmeat, bool? haspork, bool? hasanimal, byte spicy, byte sweet, float? fatperunit, float? sugarperunit, float? caloriesperunit, float? sodiumperunit, float? carbsperunit) 23 | { 24 | HasGluten = hasgluten; 25 | HasMeat = hasmeat; 26 | HasRedMeat = hasredmeat; 27 | HasPork = haspork; 28 | HasAnimal = hasanimal; 29 | Spicy = spicy; 30 | Sweet = sweet; 31 | FatPerUnit = fatperunit; 32 | SugarPerUnit = sugarperunit; 33 | CaloriesPerUnit = caloriesperunit; 34 | SodiumPerUnit = sodiumperunit; 35 | CarbsPerUnit = carbsperunit; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.Ingredients 6 | { 7 | public class IngredientSection 8 | { 9 | public string SectionName { get; private set; } 10 | public IngredientUsageCollection Ingredients { get; private set; } 11 | 12 | IngredientSection(string name) 13 | { 14 | SectionName = name; 15 | Ingredients = new IngredientUsageCollection(); 16 | } 17 | 18 | public static IngredientSection[] GetSections(Recipe recipe) 19 | { 20 | //TODO: This code can probably be done in a LINQ expression, or more efficiently. 21 | 22 | var nullSection = new IngredientSection(null); 23 | var map = new Dictionary(); 24 | 25 | foreach (var usage in recipe.Ingredients) 26 | { 27 | if (String.IsNullOrEmpty(usage.Section)) 28 | { 29 | nullSection.Ingredients.Add(usage); 30 | } 31 | else 32 | { 33 | var sectionKey = usage.Section.ToLower(); 34 | 35 | IngredientSection sectionList; 36 | if (map.TryGetValue(sectionKey, out sectionList)) 37 | { 38 | sectionList.Ingredients.Add(usage); 39 | } 40 | else 41 | { 42 | sectionList = new IngredientSection(usage.Section); 43 | sectionList.Ingredients.Add(usage); 44 | map.Add(sectionKey, sectionList); 45 | } 46 | } 47 | } 48 | 49 | var ret = new List(); 50 | if (nullSection.Ingredients.Count > 0) 51 | { 52 | ret.Add(nullSection); 53 | } 54 | 55 | ret.AddRange(map.Values); 56 | 57 | return ret.ToArray(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Core/Ingredients/IngredientUsageCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.Ingredients 4 | { 5 | public class IngredientUsageCollection : List 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/Core/Linq/Enumerable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace KitchenPC.Linq 6 | { 7 | /// Linq extensions for KitchenPC data types 8 | public static class Enumerable 9 | { 10 | public static Amount Sum(this IEnumerable source) 11 | { 12 | var total = new Amount(); 13 | 14 | return source.Aggregate(total, (current, a) => current + a); 15 | } 16 | 17 | public static Amount Sum(this IEnumerable source, Func selector) 18 | { 19 | var total = new Amount(); 20 | 21 | return source.Aggregate(total, (current, a) => (Amount) (current + selector(a))); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/Menus/GetMenuOptions.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Menus 2 | { 3 | public class GetMenuOptions 4 | { 5 | public bool LoadRecipes; 6 | 7 | static readonly GetMenuOptions none = new GetMenuOptions(); 8 | static readonly GetMenuOptions loaded = new GetMenuOptions {LoadRecipes = true}; 9 | 10 | public static GetMenuOptions None 11 | { 12 | get 13 | { 14 | return none; 15 | } 16 | } 17 | 18 | public static GetMenuOptions WithRecipes 19 | { 20 | get 21 | { 22 | return loaded; 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Core/Menus/Menu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Menus 5 | { 6 | public struct Menu 7 | { 8 | public Guid? Id; 9 | public String Title; 10 | public RecipeBrief[] Recipes; //Can be null 11 | 12 | public static Menu FromId(Guid menuId) 13 | { 14 | return new Menu(menuId, null); 15 | } 16 | 17 | static readonly Menu favorites = new Menu(null, "Favorites"); 18 | 19 | public static Menu Favorites 20 | { 21 | get 22 | { 23 | return favorites; 24 | } 25 | } 26 | 27 | public Menu(Guid? id, String title) 28 | { 29 | Id = id; 30 | Title = title; 31 | Recipes = null; 32 | } 33 | 34 | public Menu(Menu menu) 35 | { 36 | Id = menu.Id; 37 | Title = menu.Title; 38 | Recipes = null; 39 | 40 | if (menu.Recipes != null) 41 | { 42 | Recipes = new RecipeBrief[menu.Recipes.Length]; 43 | menu.Recipes.CopyTo(Recipes, 0); 44 | } 45 | } 46 | 47 | public override string ToString() 48 | { 49 | var count = (Recipes != null ? Recipes.Length : 0); 50 | 51 | return String.Format("{0} ({1} {2}", 52 | Title, 53 | count, 54 | count != 1 ? "recipes" : "recipe"); 55 | } 56 | 57 | public override bool Equals(object obj) 58 | { 59 | if (false == (obj is Menu)) 60 | return false; 61 | 62 | var menu = (Menu) obj; 63 | if (this.Id.HasValue || menu.Id.HasValue) 64 | return this.Id.Equals(menu.Id); 65 | 66 | return this.Title.Equals(menu.Title); 67 | } 68 | 69 | public override int GetHashCode() 70 | { 71 | return this.Id.HasValue ? this.Id.Value.GetHashCode() : this.Title.GetHashCode(); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/Core/Menus/MenuMove.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Menus 4 | { 5 | public class MenuMove 6 | { 7 | public Guid? TargetMenu { get; set; } 8 | public Guid[] RecipesToMove { get; set; } 9 | public bool MoveAll { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Menus/MenuResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Menus 4 | { 5 | public class MenuResult 6 | { 7 | public bool MenuCreated; 8 | public bool MenuUpdated; 9 | 10 | public Guid? NewMenuId; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Modeler/CompiledModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | /// 7 | /// A fully compiled result set from the modeler containing full recipe briefs and ingredient aggregation data. 8 | /// 9 | public class CompiledModel 10 | { 11 | static CompiledModel empty; 12 | 13 | public RecipeBrief[] Briefs; 14 | public Guid[] RecipeIds { get; set; } 15 | public PantryItem[] Pantry { get; set; } 16 | public SuggestedRecipe[] Recipes { get; set; } 17 | 18 | public int Count 19 | { 20 | get 21 | { 22 | return (Recipes == null ? 0 : Recipes.Length); 23 | } 24 | set 25 | { 26 | } 27 | } 28 | 29 | public static CompiledModel Empty 30 | { 31 | get 32 | { 33 | if (empty == null) 34 | { 35 | empty = new CompiledModel() 36 | { 37 | Briefs = new RecipeBrief[0], 38 | Pantry = new PantryItem[0], 39 | RecipeIds = new Guid[0], 40 | Recipes = new SuggestedRecipe[0] 41 | }; 42 | } 43 | 44 | return empty; 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Core/Modeler/IModelerLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.Modeler 4 | { 5 | public interface IModelerLoader 6 | { 7 | IEnumerable LoadRecipeGraph(); 8 | IEnumerable LoadIngredientGraph(); 9 | IEnumerable LoadRatingGraph(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Modeler/IUserProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | /// 7 | /// Interface used to transfer user specific runtime properties into the modeler. KPC will be implementation that builds 8 | /// this information from the database, and unit tests will create static instances for testing. 9 | /// 10 | public interface IUserProfile 11 | { 12 | Guid UserId { get; } //DB User ID 13 | RecipeRating[] Ratings { get; } //Every recipe ID user has rated with the rating 14 | PantryItem[] Pantry { get; } //Set of ingredients user has available with amounts 15 | Guid[] FavoriteIngredients { get; } //Ingredients to favor 16 | RecipeTags FavoriteTags { get; } //Tags to favor 17 | Guid[] BlacklistedIngredients { get; } //Ingredients to always avoid 18 | Guid? AvoidRecipe { get; } 19 | RecipeTags AllowedTags { get; } //Only allow recipes that contain at least one of these tags (null to allow all) 20 | } 21 | } -------------------------------------------------------------------------------- /src/Core/Modeler/IngredientBinding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | public struct IngredientBinding 7 | { 8 | public Guid RecipeId { get; set; } 9 | public Guid IngredientId { get; set; } 10 | public Single? Qty { get; set; } 11 | public Units Unit { get; set; } 12 | 13 | public static IngredientBinding Create(Guid ingId, Guid recipeId, Single? qty, Units usageUnit, UnitType convType, Int32 unitWeight, 14 | Units formUnit, Single equivAmount, Units equivUnit) 15 | { 16 | var rawUnit = KitchenPC.Unit.GetDefaultUnitType(convType); 17 | 18 | if (qty.HasValue && rawUnit != usageUnit) 19 | { 20 | if (UnitConverter.CanConvert(usageUnit, rawUnit)) 21 | { 22 | qty = UnitConverter.Convert(qty.Value, usageUnit, rawUnit); 23 | } 24 | else 25 | { 26 | var ing = new Ingredient 27 | { 28 | Id = ingId, 29 | ConversionType = convType, 30 | UnitWeight = unitWeight 31 | }; 32 | 33 | var form = new IngredientForm 34 | { 35 | FormUnitType = formUnit, 36 | FormAmount = new Amount(equivAmount, equivUnit), 37 | IngredientId = ingId 38 | }; 39 | 40 | var usage = new Ingredients.IngredientUsage 41 | { 42 | Form = form, 43 | Ingredient = ing, 44 | Amount = new Amount(qty.Value, usageUnit) 45 | }; 46 | 47 | try 48 | { 49 | var newAmt = FormConversion.GetNativeAmountForUsage(ing, usage); 50 | qty = UnitConverter.Convert(newAmt.SizeHigh, newAmt.Unit, rawUnit); //Ingredient graph only stores high amounts 51 | } 52 | catch (Exception e) 53 | { 54 | throw new DataLoadException(e); 55 | } 56 | } 57 | } 58 | 59 | return new IngredientBinding 60 | { 61 | RecipeId = recipeId, 62 | IngredientId = ingId, 63 | Qty = qty.HasValue ? (float?) Math.Round(qty.Value, 3) : null, 64 | Unit = rawUnit 65 | }; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/Core/Modeler/IngredientNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.Modeler 6 | { 7 | public sealed class IngredientNode 8 | { 9 | public static int NextKey = 0; 10 | 11 | public Int32 Key; //Interally, ingredients will have numeric keys for faster hashing 12 | public Guid IngredientId; //KPC Shopping Ingredient ID 13 | public UnitType ConvType; //Conversion type for this ingredient 14 | public IEnumerable[] RecipesByTag; //Recipes that use this ingredient (does not include Hidden recipes) 15 | public RecipeTags AvailableTags; //Which indices in RecipesByTag are not null 16 | 17 | public IngredientNode() 18 | { 19 | this.Key = NextKey++; 20 | } 21 | 22 | public override int GetHashCode() 23 | { 24 | return Key; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Core/Modeler/IngredientUsage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Modeler 4 | { 5 | public struct IngredientUsage 6 | { 7 | public IngredientNode Ingredient; //Reference to IngredientNode describing this ingredient 8 | public Single? Amt; //Amount of ingredient, expressed in default units for ingredient 9 | public Units Unit; //Unit for this amount (will always be compatible with Ingredient.ConvType) 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Modeler/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | /// 7 | /// This contains a model generated by a modeling session. The RecipeIDs contain the suggested recipes to make, and the leftover amounts indicate 8 | /// the quantity of given ingredients that would be left in the user's pantry after making the suggested recipes. 9 | /// 10 | public class Model 11 | { 12 | readonly Guid[] _recipeids; 13 | readonly PantryItem[] _pantry; 14 | readonly double _score; 15 | 16 | public Guid[] RecipeIds 17 | { 18 | get 19 | { 20 | return _recipeids; 21 | } 22 | } 23 | 24 | public PantryItem[] Pantry 25 | { 26 | get 27 | { 28 | return _pantry; 29 | } 30 | } 31 | 32 | public int Count 33 | { 34 | get 35 | { 36 | return _recipeids.Length; 37 | } 38 | } 39 | 40 | public double Score 41 | { 42 | get 43 | { 44 | return _score; 45 | } 46 | } 47 | 48 | public Model(RecipeNode[] recipes, PantryItem[] pantry, double score) 49 | { 50 | this._recipeids = recipes.Select(r => { return r.RecipeId; }).ToArray(); 51 | this._pantry = pantry; 52 | this._score = score; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Core/Modeler/ModelerProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Context; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | public class ModelerProxy 7 | { 8 | DBSnapshot db; 9 | readonly IKPCContext context; 10 | 11 | public ModelerProxy(IKPCContext context) 12 | { 13 | this.context = context; 14 | } 15 | 16 | public void LoadSnapshot() 17 | { 18 | db = new DBSnapshot(context); 19 | } 20 | 21 | public ModelingSession CreateSession(IUserProfile profile) 22 | { 23 | if (db == null) 24 | throw new Exception("ModelerProxy has not been initialized."); 25 | 26 | return new ModelingSession(context, db, profile); 27 | } 28 | 29 | public RecipeNode FindRecipe(Guid id) 30 | { 31 | if (db == null) 32 | throw new Exception("ModelerProxy has not been initialized."); 33 | 34 | return db.FindRecipe(id); 35 | } 36 | 37 | public IngredientNode FindIngredient(Guid id) 38 | { 39 | if (db == null) 40 | throw new Exception("ModelerProxy has not been initialized."); 41 | 42 | return db.FindIngredient(id); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Core/Modeler/ModelerQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace KitchenPC.Modeler 6 | { 7 | /// 8 | /// Represents a query for the modeler, such as a list of ingredients, recipes to avoid, and a number of recipes to return. 9 | /// 10 | public class ModelerQuery 11 | { 12 | public string[] Ingredients; //User-entered ingredients to be parsed by NLP 13 | public Guid? AvoidRecipe; //Avoid specific recipe, useful for swapping out one recipe for another 14 | public byte NumRecipes; 15 | public byte Scale; 16 | 17 | public string CacheKey 18 | { 19 | get 20 | { 21 | var bytes = new List(); 22 | bytes.Add(NumRecipes); //First byte is number of recipes 23 | bytes.Add(Scale); //Second byte is the scale 24 | 25 | if (AvoidRecipe.HasValue) 26 | bytes.AddRange(AvoidRecipe.Value.ToByteArray()); 27 | 28 | //Remaining bytes are defined ingredients, delimited by null 29 | if (Ingredients != null && Ingredients.Length > 0) 30 | { 31 | foreach (var ing in Ingredients) 32 | { 33 | bytes.AddRange(Encoding.UTF8.GetBytes(ing.ToLower().Trim())); 34 | bytes.Add(0); //Null delimiter 35 | } 36 | } 37 | 38 | return Convert.ToBase64String(bytes.ToArray()); 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/Modeler/PantryItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Modeler 4 | { 5 | public struct PantryItem 6 | { 7 | public Guid IngredientId; //KPC Shopping Ingredient ID 8 | public Single? Amt; //Optional amount of ingredient, expressed in default units for ingredient 9 | 10 | public PantryItem(Ingredients.IngredientUsage usage) 11 | { 12 | IngredientId = usage.Ingredient.Id; 13 | 14 | //Need to convert IngredientUsage into proper Pantry form 15 | if (usage.Amount != null) 16 | { 17 | var toUnit = Unit.GetDefaultUnitType(usage.Ingredient.ConversionType); 18 | if (UnitConverter.CanConvert(usage.Form.FormUnitType, toUnit)) 19 | { 20 | Amt = UnitConverter.Convert(usage.Amount, toUnit).SizeHigh; //Always take high amount for pantry items 21 | } 22 | else //Find conversion path 23 | { 24 | var amount = FormConversion.GetNativeAmountForUsage(usage.Ingredient, usage); 25 | Amt = UnitConverter.Convert(amount, toUnit).SizeHigh; //Always take high amount for pantry items 26 | } 27 | } 28 | else 29 | { 30 | Amt = null; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Core/Modeler/RatingBinding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Modeler 4 | { 5 | public struct RatingBinding 6 | { 7 | public Guid UserId { get; set; } 8 | public Guid RecipeId { get; set; } 9 | public Int16 Rating { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Modeler/RecipeBinding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | public struct RecipeBinding 7 | { 8 | public Guid Id { get; set; } 9 | public Byte Rating { get; set; } 10 | public RecipeTags Tags { get; set; } 11 | public Boolean Hidden { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Core/Modeler/RecipeNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.Modeler 6 | { 7 | public sealed class RecipeNode 8 | { 9 | static int nextkey = 0; 10 | 11 | public Int32 Key; //Internally, recipes will have numeric keys for faster hashing 12 | public Guid RecipeId; 13 | public IEnumerable Ingredients; 14 | public RecipeTags Tags; //Tags from DB 15 | public Byte Rating; //Public rating from DB 16 | public Boolean Hidden; //Recipe is hidden (won't be picked at random) 17 | public RecipeNode[] Suggestions; //Users who like this recipe might also like these recipes (in order of weight) 18 | 19 | public RecipeNode() 20 | { 21 | this.Key = nextkey++; 22 | } 23 | 24 | public override int GetHashCode() 25 | { 26 | return Key; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Core/Modeler/RecipeRating.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Modeler 4 | { 5 | public struct RecipeRating 6 | { 7 | public Guid RecipeId; 8 | public Byte Rating; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/Modeler/SuggestedRecipe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | /// 7 | /// A recipe suggested by the modeler. 8 | /// 9 | public class SuggestedRecipe 10 | { 11 | public Guid Id { get; set; } 12 | public IngredientAggregation[] Ingredients { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/Modeler/UserProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Modeler 5 | { 6 | public class UserProfile : IUserProfile 7 | { 8 | static IUserProfile anonymous; 9 | 10 | /// 11 | /// Represents a modeling profile that has no user context, such as a saved pantry, favorite ingredients, blacklists, etc. 12 | /// 13 | public static IUserProfile Anonymous 14 | { 15 | get 16 | { 17 | if (anonymous == null) 18 | { 19 | anonymous = new UserProfile 20 | { 21 | UserId = Guid.Empty, 22 | Ratings = new RecipeRating[0], 23 | FavoriteIngredients = new Guid[0], 24 | FavoriteTags = RecipeTags.None, 25 | BlacklistedIngredients = new Guid[0] 26 | }; 27 | } 28 | 29 | return anonymous; 30 | } 31 | } 32 | 33 | public Guid UserId { get; set; } 34 | public RecipeRating[] Ratings { get; set; } 35 | public PantryItem[] Pantry { get; set; } 36 | public Guid[] FavoriteIngredients { get; set; } 37 | public RecipeTags FavoriteTags { get; set; } 38 | public Guid[] BlacklistedIngredients { get; set; } 39 | public Guid? AvoidRecipe { get; set; } 40 | public RecipeTags AllowedTags { get; set; } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/NLP/AlphaTree.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class AlphaTree 4 | { 5 | public Node Head; 6 | 7 | public AlphaTree() 8 | { 9 | Head = new Node(); 10 | } 11 | 12 | public class Node 13 | { 14 | public Node[] nodes; 15 | public ConnectorVertex connections; 16 | 17 | public Node() 18 | { 19 | nodes = new Node[94]; 20 | } 21 | 22 | public Node AddLink(char c) 23 | { 24 | var index = c - 32; 25 | return (nodes[index] = new Node()); 26 | } 27 | 28 | public bool HasLink(char c) 29 | { 30 | var index = c - 32; 31 | return (nodes[index] != null); 32 | } 33 | 34 | public Node GetLink(char c) 35 | { 36 | var index = c - 32; 37 | return nodes[index]; 38 | } 39 | 40 | public void AddConnection(T node) 41 | { 42 | if (connections == null) 43 | { 44 | connections = new ConnectorVertex(); 45 | } 46 | else 47 | { 48 | if (connections.HasConnection(node)) 49 | return; 50 | } 51 | 52 | connections.AddConnection(node); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Core/NLP/Anomalies.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class Anomalies : SynonymTree 6 | { 7 | static readonly object MapInitLock = new object(); 8 | 9 | public static void InitIndex(ISynonymLoader loader) 10 | { 11 | lock (MapInitLock) 12 | { 13 | index = new AlphaTree(); 14 | synonymMap = new Dictionary(); 15 | var anomalies = loader.LoadSynonyms(); 16 | 17 | foreach (var anom in anomalies) 18 | { 19 | IndexString(anom.Name, anom); 20 | } 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/NLP/AnomalousIngredientNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class AnomalousIngredientNode : IngredientNode 6 | { 7 | public AnomalousIngredientNode(Guid id, string name, UnitType convtype, Weight unitweight, DefaultPairings pairings) : base(id, name, convtype, unitweight, pairings) 8 | { 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/NLP/AnomalousMatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public class AnomalousMatch : Match 7 | { 8 | readonly AnomalousResult anomaly; 9 | 10 | public AnomalousMatch(string input, AnomalousResult anomaly, IngredientUsage usage) : base(input, usage) 11 | { 12 | this.anomaly = anomaly; 13 | } 14 | 15 | public override string ToString() 16 | { 17 | return String.Format("[AnomalousMatch] ({0}) Usage: {1}", anomaly, usage); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Core/NLP/AnomalousNode.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class AnomalousNode 4 | { 5 | public string Name; 6 | public AnomalousIngredientNode Ingredient; 7 | 8 | public AnomalousNode(string name, AnomalousIngredientNode ing) 9 | { 10 | Name = name; 11 | Ingredient = ing; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/NLP/ConnectorVertex.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public class ConnectorVertex 7 | { 8 | readonly List connections; 9 | 10 | public ConnectorVertex() 11 | { 12 | connections = new List(); 13 | } 14 | 15 | public void AddConnection(T node) 16 | { 17 | connections.Add(node); 18 | } 19 | 20 | public bool HasConnection(T node) 21 | { 22 | return connections.Contains(node); 23 | } 24 | 25 | public IEnumerable GetConnections() 26 | { 27 | var e = connections.GetEnumerator(); 28 | while (e.MoveNext()) 29 | { 30 | yield return e.Current; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Core/NLP/CustomUnitNode.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class CustomUnitNode : UnitNode 4 | { 5 | public CustomUnitNode(string name) : base(name, Units.Unit) 6 | { 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/NLP/DefaultPairings.cs: -------------------------------------------------------------------------------- 1 | using KitchenPC.Ingredients; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public struct DefaultPairings 6 | { 7 | static readonly DefaultPairings empty = new DefaultPairings(); 8 | 9 | public static DefaultPairings Empty 10 | { 11 | get 12 | { 13 | return empty; 14 | } 15 | } 16 | 17 | public IngredientForm Unit; 18 | public IngredientForm Volume; 19 | public IngredientForm Weight; 20 | 21 | public bool IsEmpty 22 | { 23 | get 24 | { 25 | return (Unit == null && Volume == null && Weight == null); 26 | } 27 | } 28 | 29 | public bool HasUnit 30 | { 31 | get 32 | { 33 | return Unit != null; 34 | } 35 | } 36 | 37 | public bool HasVolume 38 | { 39 | get 40 | { 41 | return Volume != null; 42 | } 43 | } 44 | 45 | public bool HasWeight 46 | { 47 | get 48 | { 49 | return Weight != null; 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/Core/NLP/DefaultTracer.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | /// Implementation of ITracer that uses Log4Net 6 | public class DefaultTracer : ITracer 7 | { 8 | readonly ILog log; 9 | 10 | public DefaultTracer() 11 | { 12 | log = LogManager.GetLogger(typeof (Parser)); 13 | log.Info("Initialized logger for new NLP parser."); 14 | } 15 | 16 | public void Trace(TraceLevel level, string message, params object[] args) 17 | { 18 | switch (level) 19 | { 20 | case TraceLevel.Debug: 21 | log.DebugFormat(message, args); 22 | break; 23 | case TraceLevel.Error: 24 | log.ErrorFormat(message, args); 25 | break; 26 | case TraceLevel.Fatal: 27 | log.FatalFormat(message, args); 28 | break; 29 | case TraceLevel.Info: 30 | log.InfoFormat(message, args); 31 | break; 32 | case TraceLevel.Warn: 33 | log.WarnFormat(message, args); 34 | break; 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Core/NLP/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public enum MatchPrecision 4 | { 5 | None, 6 | Partial, 7 | Exact 8 | }; 9 | 10 | public enum MatchResult 11 | { 12 | NoMatch, 13 | UnknownUnit, 14 | NoForm, 15 | UnknownForm, 16 | IncompatibleForm, 17 | PartialMatch, 18 | Match 19 | } 20 | 21 | public enum AnomalousResult 22 | { 23 | Fallthrough, 24 | AutoConvert 25 | } 26 | 27 | public enum TraceLevel 28 | { 29 | Debug, 30 | Error, 31 | Info, 32 | Fatal, 33 | Warn 34 | } 35 | } -------------------------------------------------------------------------------- /src/Core/NLP/FormNode.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class FormNode 4 | { 5 | public string FormName; 6 | 7 | public FormNode(string name) 8 | { 9 | FormName = name.Trim(); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/NLP/FormSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KitchenPC.Ingredients; 4 | 5 | namespace KitchenPC.NLP 6 | { 7 | public class FormSynonyms : SynonymTree 8 | { 9 | static readonly object MapInitLock = new object(); 10 | static Pairings pairings; 11 | 12 | public static void InitIndex(ISynonymLoader loader) 13 | { 14 | lock (MapInitLock) 15 | { 16 | index = new AlphaTree(); 17 | synonymMap = new Dictionary(); 18 | 19 | foreach (var form in loader.LoadSynonyms()) 20 | { 21 | IndexString(form.FormName, form); 22 | } 23 | 24 | pairings = loader.LoadFormPairings(); 25 | } 26 | } 27 | 28 | public static bool TryGetFormForIngredient(string formname, Guid ing, out IngredientForm form) 29 | { 30 | form = null; 31 | FormNode node; 32 | if (false == synonymMap.TryGetValue(formname, out node)) 33 | { 34 | return false; 35 | } 36 | 37 | var pair = new NameIngredientPair(formname, ing); 38 | return pairings.TryGetValue(pair, out form); 39 | } 40 | 41 | public static bool TryGetFormForPrep(Preps preps, IngredientNode ing, bool remove, out IngredientForm form) 42 | { 43 | //TODO: Do we need to check all preps, or just the one that was on the input 44 | foreach (var prep in preps) 45 | { 46 | var fMatch = TryGetFormForIngredient(prep.Prep, ing.Id, out form); 47 | if (!fMatch) continue; 48 | 49 | if (remove) 50 | preps.Remove(prep); 51 | 52 | return true; 53 | } 54 | 55 | form = null; 56 | return false; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/Core/NLP/IGrammar.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public interface IGrammar 6 | { 7 | /// 8 | /// Reads stream of ingredient usage being parsed and modifies IngredientUsage as fit 9 | /// 10 | /// Stream containing input 11 | /// Usage to modify when data becomes known 12 | /// 13 | bool Read(Stream stream, MatchData usage); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/NLP/ISynonymLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public interface ISynonymLoader 6 | { 7 | IEnumerable LoadSynonyms(); 8 | Pairings LoadFormPairings(); //Default pairing data for forms of certain ingredients 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/NLP/ITracer.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public interface ITracer 4 | { 5 | void Trace(TraceLevel level, string message, params object[] args); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/NLP/IngredientNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class IngredientNode 6 | { 7 | readonly IngredientNode parent; //This node can shadow another node under another name 8 | readonly Guid id; 9 | readonly DefaultPairings pairings; 10 | readonly UnitType convtype; 11 | readonly Weight unitweight; 12 | 13 | public Guid Id 14 | { 15 | get 16 | { 17 | return (parent == null) ? id : parent.id; 18 | } 19 | } 20 | 21 | public DefaultPairings Pairings 22 | { 23 | get 24 | { 25 | return (parent == null) ? pairings : parent.pairings; 26 | } 27 | } 28 | 29 | public IngredientNode Parent 30 | { 31 | get 32 | { 33 | return parent; 34 | } 35 | } 36 | 37 | public string IngredientName; //Name of the ingredient or synonym 38 | public string PrepNote; //If this ingredient is an alias for another, it will use this as a prep note, eg: Ripe Bananas => Bananas (Ripe) 39 | 40 | public UnitType ConversionType 41 | { 42 | get 43 | { 44 | return (parent == null) ? convtype : parent.convtype; 45 | } 46 | } //Default conversion type for this ingredient (from ShoppingIngredients) 47 | 48 | public Weight UnitWeight 49 | { 50 | get 51 | { 52 | return (parent == null) ? unitweight : parent.unitweight; 53 | } 54 | } //How much a single unit weighs (from ShoppingIngredients) 55 | 56 | public IngredientNode(Guid id, string name, UnitType convtype, Weight unitweight, DefaultPairings pairings) 57 | { 58 | this.id = id; 59 | this.pairings = pairings; 60 | this.convtype = convtype; 61 | this.unitweight = unitweight; 62 | 63 | IngredientName = name; 64 | } 65 | 66 | public IngredientNode(IngredientNode root, string synonym, string prepnote) 67 | { 68 | this.parent = root; 69 | IngredientName = synonym; 70 | PrepNote = prepnote; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/Core/NLP/IngredientSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class IngredientSynonyms : SynonymTree 6 | { 7 | static readonly object MapInitLock = new object(); 8 | 9 | public static void InitIndex(ISynonymLoader loader) 10 | { 11 | lock (MapInitLock) 12 | { 13 | index = new AlphaTree(); 14 | synonymMap = new Dictionary(); 15 | var ings = loader.LoadSynonyms(); 16 | 17 | foreach (var ing in ings) 18 | { 19 | IndexString(ing.IngredientName, ing); 20 | } 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/NLP/Match.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public class Match : Result 7 | { 8 | protected IngredientUsage usage; 9 | 10 | public override IngredientUsage Usage 11 | { 12 | get 13 | { 14 | return usage; 15 | } 16 | } 17 | 18 | public override MatchResult Status 19 | { 20 | get 21 | { 22 | return MatchResult.Match; 23 | } 24 | } 25 | 26 | public Match(string input, IngredientUsage usage) : base(input) 27 | { 28 | this.usage = usage; 29 | } 30 | 31 | public override string ToString() 32 | { 33 | return String.Format("[Match] Usage: {0}", usage); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Core/NLP/MatchData.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class MatchData 4 | { 5 | public IngredientNode Ingredient; 6 | public UnitNode Unit; 7 | public FormNode Form; 8 | public Amount Amount; 9 | public Preps Preps; 10 | 11 | public MatchData() 12 | { 13 | Preps = new Preps(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Core/NLP/NameIngredientPair.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class NameIngredientPair 6 | { 7 | readonly int hash; 8 | public string Name { get; set; } 9 | public Guid IngredientId { get; set; } 10 | 11 | public NameIngredientPair(string name, Guid id) 12 | { 13 | this.Name = name; 14 | this.IngredientId = id; 15 | this.hash = (name + id.ToString()).GetHashCode(); 16 | } 17 | 18 | public override int GetHashCode() 19 | { 20 | return this.hash; 21 | } 22 | 23 | public override bool Equals(object obj) 24 | { 25 | var pair = obj as NameIngredientPair; 26 | 27 | if (obj == null) 28 | return false; 29 | 30 | return (this.Name == pair.Name && this.IngredientId == pair.IngredientId); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Core/NLP/NlpTracer.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public static class NlpTracer 4 | { 5 | static ITracer currentTracer; 6 | 7 | public static void SetTracer(ITracer tracer) 8 | { 9 | currentTracer = tracer; //BUGBUG: Not thread safe, but probably not tracing on the main site 10 | } 11 | 12 | public static void Trace(TraceLevel level, string message, params object[] args) 13 | { 14 | if (currentTracer == null) //No op 15 | { 16 | return; 17 | } 18 | 19 | currentTracer.Trace(level, message, args); 20 | } 21 | 22 | public static void ConditionalTrace(bool condition, TraceLevel level, string message, params object[] args) 23 | { 24 | if (condition) 25 | { 26 | Trace(level, message, args); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Core/NLP/NoMatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class NoMatch : Result 6 | { 7 | readonly MatchResult status; 8 | 9 | public override MatchResult Status 10 | { 11 | get 12 | { 13 | return status; 14 | } 15 | } 16 | 17 | public NoMatch(string input, MatchResult status) : base(input) 18 | { 19 | this.status = status; 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return String.Format("[NoMatch] Error: {0}", status); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Core/NLP/NumericNode.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class NumericNode 4 | { 5 | public string Token; 6 | public float Value; 7 | 8 | public NumericNode(string token, float value) 9 | { 10 | Token = token; 11 | Value = value; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/NLP/NumericVocab.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class NumericVocab : SynonymTree 6 | { 7 | static readonly object MapInitLock = new object(); 8 | 9 | public static void InitIndex() 10 | { 11 | lock (MapInitLock) 12 | { 13 | index = new AlphaTree(); 14 | synonymMap = new Dictionary(); 15 | 16 | //Basic numbers, we can add more if needed 17 | string[] numbers = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; 18 | for (var i = 0; i < numbers.Length; i++) 19 | { 20 | IndexString(numbers[i], new NumericNode(numbers[i], i + 1)); 21 | } 22 | 23 | //Other numeric tokens 24 | NumericNode[] tokens = 25 | { 26 | new NumericNode("a", 1), 27 | new NumericNode("an", 1), 28 | new NumericNode("half a", 0.5f), 29 | new NumericNode("half of a", 0.5f), 30 | new NumericNode("half an", 0.5f), 31 | new NumericNode("half of an", 0.5f), 32 | new NumericNode("a dozen", 12), 33 | new NumericNode("one dozen", 12), 34 | new NumericNode("a couple", 2), 35 | new NumericNode("a couple of", 2) 36 | }; 37 | 38 | foreach (var t in tokens) 39 | { 40 | IndexString(t.Token, t); 41 | } 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Core/NLP/Pairings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public class Pairings 7 | { 8 | readonly IDictionary pairs; 9 | 10 | public Pairings() 11 | { 12 | pairs = new Dictionary(); 13 | } 14 | 15 | public void Add(NameIngredientPair key, IngredientForm value) 16 | { 17 | pairs.Add(key, value); 18 | } 19 | 20 | public bool ContainsKey(NameIngredientPair key) 21 | { 22 | return pairs.ContainsKey(key); 23 | } 24 | 25 | public bool TryGetValue(NameIngredientPair key, out IngredientForm value) 26 | { 27 | return pairs.TryGetValue(key, out value); 28 | } 29 | 30 | public IngredientForm this[NameIngredientPair key] 31 | { 32 | get 33 | { 34 | return pairs[key]; 35 | } 36 | set 37 | { 38 | pairs[key] = value; 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/NLP/PartialMatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public class PartialMatch : Match 7 | { 8 | public override MatchResult Status 9 | { 10 | get 11 | { 12 | return MatchResult.PartialMatch; 13 | } 14 | } 15 | 16 | public PartialMatch(string input, Ingredient ingredient, string prep) : base(input, null) 17 | { 18 | this.usage = new IngredientUsage(ingredient, null, null, prep); 19 | } 20 | 21 | public override string ToString() 22 | { 23 | if (String.IsNullOrEmpty(usage.PrepNote)) 24 | return String.Format("[PartialMatch] Ingredient: {0}", usage.Ingredient.Name); 25 | else 26 | return String.Format("[PartialMatch] Ingredient: {0} ({1})", usage.Ingredient.Name, usage.PrepNote); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Core/NLP/PrepNode.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.NLP 2 | { 3 | public class PrepNode 4 | { 5 | public string Prep; 6 | 7 | public PrepNode(string prep) 8 | { 9 | Prep = prep.ToLower().Trim(); 10 | } 11 | 12 | public static implicit operator PrepNode(string p) 13 | { 14 | return new PrepNode(p); 15 | } 16 | 17 | public static implicit operator string(PrepNode p) 18 | { 19 | return p.Prep; 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return Prep; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Core/NLP/PrepNotes.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class PrepNotes : SynonymTree 6 | { 7 | static readonly object MapInitLock = new object(); 8 | 9 | public static void InitIndex(ISynonymLoader loader) 10 | { 11 | lock (MapInitLock) 12 | { 13 | index = new AlphaTree(); 14 | synonymMap = new Dictionary(); 15 | var preps = loader.LoadSynonyms(); 16 | 17 | foreach (var prep in preps) 18 | { 19 | IndexString(prep.Prep, prep); 20 | } 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/NLP/Preps.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace KitchenPC.NLP 7 | { 8 | public class Preps : IEnumerable 9 | { 10 | readonly List notes; 11 | 12 | public Preps() 13 | { 14 | notes = new List(); 15 | } 16 | 17 | public bool HasValue 18 | { 19 | get 20 | { 21 | return notes.Count != 0; 22 | } 23 | } 24 | 25 | public void Add(PrepNode prep) 26 | { 27 | notes.Add(prep); 28 | } 29 | 30 | public void Remove(PrepNode node) 31 | { 32 | notes.Remove(node); 33 | } 34 | 35 | public override string ToString() 36 | { 37 | if (notes.Count == 0) 38 | { 39 | return String.Empty; 40 | } 41 | 42 | return String.Join("//", notes.Select(p => { return p.Prep; }).ToArray()); 43 | } 44 | 45 | public IEnumerator GetEnumerator() 46 | { 47 | return notes.GetEnumerator(); 48 | } 49 | 50 | IEnumerator IEnumerable.GetEnumerator() 51 | { 52 | return notes.GetEnumerator(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Core/NLP/SynonymTree.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace KitchenPC.NLP 5 | { 6 | public abstract class SynonymTree 7 | { 8 | protected static AlphaTree index; 9 | protected static Dictionary synonymMap; 10 | 11 | protected static void IndexString(string value, T node) 12 | { 13 | var parsedIng = value.Trim().ToLower(); 14 | 15 | if (synonymMap.ContainsKey(parsedIng)) //Uh oh 16 | { 17 | Parser.Log.Error(String.Format("The ingredient synonym '{0}' also exists as a root ingredient.", value)); 18 | } 19 | else 20 | { 21 | synonymMap.Add(parsedIng, node); 22 | } 23 | 24 | var curNode = index.Head; 25 | for (var i = 0; i < parsedIng.Length; i++) 26 | { 27 | var c = parsedIng[i]; 28 | if (curNode.HasLink(c) == false) 29 | { 30 | curNode = curNode.AddLink(c); 31 | } 32 | else 33 | { 34 | curNode = curNode.GetLink(c); 35 | } 36 | 37 | curNode.AddConnection(node); 38 | } 39 | } 40 | 41 | public MatchPrecision Parse(string substr, out T match) 42 | { 43 | substr = substr.TrimStart(' '); //Strip off any leading spaces, an empty string will always return "Partial" so processing will continue 44 | 45 | if (synonymMap.TryGetValue(substr, out match)) //If they pass in a complete ingredient name, return Exact 46 | { 47 | return MatchPrecision.Exact; 48 | } 49 | 50 | //Figure out if this is a partial match for an ingredient 51 | var node = index.Head; 52 | 53 | for (var i = 0; i < substr.Length; i++) 54 | { 55 | if (node.HasLink(substr[i]) == false) //No possible match here 56 | return MatchPrecision.None; 57 | 58 | node = node.GetLink(substr[i]); 59 | } 60 | 61 | //match = null; 62 | return MatchPrecision.Partial; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Core/NLP/TemplateStatistics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace KitchenPC.NLP 6 | { 7 | public class TemplateStatistics : IEnumerable 8 | { 9 | public struct TemplateUsage 10 | { 11 | public string Template; 12 | public int Matches; 13 | 14 | public override string ToString() 15 | { 16 | return String.Format("{0} ---> {1} matches\n", Template, Matches); 17 | } 18 | } 19 | 20 | readonly Dictionary stats; 21 | 22 | public int this[Template t] 23 | { 24 | get 25 | { 26 | return stats[t]; 27 | } 28 | set 29 | { 30 | stats[t] = value; 31 | } 32 | } 33 | 34 | public TemplateStatistics() 35 | { 36 | stats = new Dictionary(); 37 | } 38 | 39 | public void RecordTemplate(Template template) 40 | { 41 | stats[template] = 0; 42 | } 43 | 44 | public IEnumerator GetEnumerator() 45 | { 46 | var e = stats.GetEnumerator(); 47 | while (e.MoveNext()) 48 | { 49 | yield return new TemplateUsage() {Template = e.Current.Key.ToString(), Matches = e.Current.Value}; 50 | } 51 | } 52 | 53 | IEnumerator IEnumerable.GetEnumerator() 54 | { 55 | var e = stats.GetEnumerator(); 56 | while (e.MoveNext()) 57 | { 58 | yield return new TemplateUsage() {Template = e.Current.Key.ToString(), Matches = e.Current.Value}; 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/AnomToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class AnomToken : IGrammar 7 | { 8 | static Anomalies data; 9 | 10 | public bool Read(Stream stream, MatchData matchData) 11 | { 12 | if (data == null) 13 | { 14 | data = new Anomalies(); 15 | } 16 | 17 | var buffer = String.Empty; 18 | AnomalousNode foundNode = null; 19 | var fFound = false; 20 | var matchPos = stream.Position; 21 | int curByte; 22 | 23 | while ((curByte = stream.ReadByte()) >= 0) 24 | { 25 | buffer += (char) curByte; 26 | 27 | AnomalousNode node; 28 | var match = data.Parse(buffer, out node); 29 | if (match == MatchPrecision.None) 30 | { 31 | break; //No reason to continue reading stream, let's see what we have.. 32 | } 33 | 34 | if (match == MatchPrecision.Exact) 35 | { 36 | matchPos = stream.Position; 37 | foundNode = node; 38 | fFound = true; 39 | } 40 | } 41 | 42 | if (foundNode != null) //Initialize match data with values from this anomaly 43 | { 44 | matchData.Ingredient = foundNode.Ingredient; 45 | } 46 | 47 | stream.Seek(matchPos, SeekOrigin.Begin); 48 | return fFound; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/FormToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class FormToken : IGrammar 7 | { 8 | static FormSynonyms data; 9 | 10 | /// 11 | /// Reads stream to match it against a dictionary of all known forms 12 | /// 13 | /// 14 | /// 15 | /// 16 | public bool Read(Stream stream, MatchData matchdata) 17 | { 18 | if (data == null) 19 | { 20 | data = new FormSynonyms(); 21 | } 22 | 23 | FormNode node; 24 | matchdata.Form = null; 25 | var buffer = String.Empty; 26 | var matchPos = stream.Position; 27 | int curByte; 28 | 29 | while ((curByte = stream.ReadByte()) >= 0) 30 | { 31 | buffer += (char) curByte; 32 | var match = data.Parse(buffer, out node); 33 | if (match == MatchPrecision.None) 34 | { 35 | break; //No reason to continue reading stream, let's see what we have.. 36 | } 37 | 38 | if (match == MatchPrecision.Exact) 39 | { 40 | matchPos = stream.Position; 41 | matchdata.Form = node; 42 | } 43 | } 44 | 45 | stream.Seek(matchPos, SeekOrigin.Begin); 46 | return (matchdata.Form != null); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/IngToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class IngToken : IGrammar 7 | { 8 | static IngredientSynonyms data; 9 | 10 | /// 11 | /// Reads stream to match it against a dictionary of all known ingredients and their aliases 12 | /// 13 | /// 14 | /// 15 | /// 16 | public bool Read(Stream stream, MatchData matchdata) 17 | { 18 | if (data == null) 19 | { 20 | data = new IngredientSynonyms(); 21 | } 22 | 23 | IngredientNode node; 24 | matchdata.Ingredient = null; 25 | var buffer = String.Empty; 26 | var matchPos = stream.Position; 27 | int curByte; 28 | 29 | while ((curByte = stream.ReadByte()) >= 0) 30 | { 31 | buffer += (char) curByte; 32 | var match = data.Parse(buffer, out node); 33 | if (match == MatchPrecision.None) 34 | { 35 | break; //No reason to continue reading stream, let's see what we have.. 36 | } 37 | 38 | if (match == MatchPrecision.Exact) 39 | { 40 | matchPos = stream.Position; 41 | matchdata.Ingredient = node; 42 | } 43 | } 44 | 45 | //Add any prep notes from this ingredient alias to the prep node collection 46 | if (matchdata.Ingredient != null && matchdata.Ingredient.PrepNote != null) 47 | { 48 | matchdata.Preps.Add(matchdata.Ingredient.PrepNote); 49 | } 50 | 51 | stream.Seek(matchPos, SeekOrigin.Begin); 52 | return (matchdata.Ingredient != null); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/NumericToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class NumericToken : IGrammar 7 | { 8 | static NumericVocab data; 9 | 10 | /// 11 | /// Reads stream to match it against a dictionary of all known units for an ingredient 12 | /// 13 | /// 14 | /// 15 | /// 16 | public bool Read(Stream stream, MatchData matchdata) 17 | { 18 | if (data == null) 19 | { 20 | data = new NumericVocab(); 21 | } 22 | 23 | NumericNode node; 24 | var fMatch = false; 25 | var buffer = String.Empty; 26 | var matchPos = stream.Position; 27 | int curByte; 28 | 29 | while ((curByte = stream.ReadByte()) >= 0) 30 | { 31 | buffer += (char) curByte; 32 | var match = data.Parse(buffer, out node); 33 | if (match == MatchPrecision.None) 34 | { 35 | stream.Seek(matchPos, SeekOrigin.Begin); 36 | break; //No reason to continue reading stream, let's see what we have.. 37 | } 38 | 39 | if (match == MatchPrecision.Exact) 40 | { 41 | matchPos = stream.Position; 42 | fMatch = true; 43 | matchdata.Amount = new Amount(); 44 | matchdata.Amount.SizeHigh = node.Value; 45 | } 46 | } 47 | 48 | return fMatch; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/PrepToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace KitchenPC.NLP.Tokens 6 | { 7 | public class PrepToken : IGrammar 8 | { 9 | static PrepNotes data; 10 | 11 | public bool Read(Stream stream, MatchData matchData) 12 | { 13 | if (data == null) 14 | { 15 | data = new PrepNotes(); 16 | } 17 | 18 | var buffer = String.Empty; 19 | PrepNode foundPrep = null; 20 | var fFound = false; 21 | var matchPos = stream.Position; 22 | int curByte; 23 | 24 | while ((curByte = stream.ReadByte()) >= 0) 25 | { 26 | buffer += (char) curByte; 27 | 28 | //Prep tokens can have leading commas or parens - so trim these off 29 | buffer = Regex.Replace(buffer, @"^\s*(,|-|\()\s*", ""); 30 | buffer = Regex.Replace(buffer, @"\s*\)\s*$", ""); 31 | 32 | PrepNode node; 33 | var match = data.Parse(buffer, out node); 34 | if (match == MatchPrecision.None) 35 | { 36 | break; //No reason to continue reading stream, let's see what we have.. 37 | } 38 | 39 | if (match == MatchPrecision.Exact) 40 | { 41 | matchPos = stream.Position; 42 | foundPrep = node; 43 | fFound = true; 44 | } 45 | } 46 | 47 | if (foundPrep != null) //Add the prep at the end of the loop in case we found multiple preps along the way 48 | { 49 | matchData.Preps.Add(foundPrep); 50 | } 51 | 52 | stream.Seek(matchPos, SeekOrigin.Begin); 53 | return fFound; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/StaticToken.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class StaticToken : IGrammar 7 | { 8 | readonly string phrase; 9 | 10 | public StaticToken(string phrase) 11 | { 12 | this.phrase = phrase.TrimStart(' '); 13 | } 14 | 15 | /// 16 | /// Reads stream to match it against a fixed string ignoring any whitespace 17 | /// 18 | /// 19 | /// 20 | /// 21 | public bool Read(Stream stream, MatchData matchdata) 22 | { 23 | while (stream.ReadByte() == ' ') 24 | { 25 | } //Burn off any leading spaces, they should not affect the grammar 26 | stream.Seek(-1, SeekOrigin.Current); //Set stream to first character after any whitespace (kinda a hack, maybe a better way to write this) 27 | 28 | //Read the stream to make sure it matches the complete token, return false if not 29 | var count = this.phrase.Length; 30 | var readBytes = new byte[count]; 31 | stream.Read(readBytes, 0, count); 32 | 33 | return (Encoding.Default.GetString(readBytes) == this.phrase); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Core/NLP/Tokens/UnitToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace KitchenPC.NLP.Tokens 5 | { 6 | public class UnitToken : IGrammar 7 | { 8 | static UnitSynonyms data; 9 | 10 | /// 11 | /// Reads stream to match it against a dictionary of all known units for an ingredient 12 | /// 13 | /// 14 | /// 15 | /// 16 | public bool Read(Stream stream, MatchData matchdata) 17 | { 18 | if (data == null) 19 | { 20 | data = new UnitSynonyms(); 21 | } 22 | 23 | UnitNode node; 24 | var fMatch = false; 25 | var buffer = String.Empty; 26 | var matchPos = stream.Position; 27 | int curByte; 28 | 29 | while ((curByte = stream.ReadByte()) >= 0) 30 | { 31 | buffer += (char) curByte; 32 | var match = data.Parse(buffer, out node); 33 | if (match == MatchPrecision.None) 34 | { 35 | stream.Seek(matchPos, SeekOrigin.Begin); 36 | break; //No reason to continue reading stream, let's see what we have.. 37 | } 38 | 39 | if (match == MatchPrecision.Exact) 40 | { 41 | matchPos = stream.Position; 42 | fMatch = true; 43 | matchdata.Amount.Unit = node.Unit; 44 | matchdata.Unit = node; 45 | } 46 | } 47 | 48 | return fMatch; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Core/NLP/UnitNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.NLP 4 | { 5 | public class UnitNode 6 | { 7 | public string Name; 8 | public Units Unit; 9 | 10 | public UnitNode(string name, Units unit) 11 | { 12 | this.Name = name.Trim(); 13 | this.Unit = unit; 14 | } 15 | 16 | public override string ToString() 17 | { 18 | if (String.IsNullOrEmpty(Name)) 19 | { 20 | return Name; 21 | } 22 | else 23 | { 24 | return Unit.ToString(); 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("KitchenPC")] 8 | [assembly: AssemblyDescription("KitchenPC Core Engine")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("KitchenPC")] 11 | [assembly: AssemblyProduct("Core")] 12 | [assembly: AssemblyCopyright("Copyright © KitchenPC 2014")] 13 | [assembly: AssemblyTrademark("KitchenPC")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("1ed3cf75-f7f5-460c-a55c-3c4523f423e7")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("0.0.9.0")] 35 | [assembly: AssemblyFileVersion("0.0.9.0")] 36 | -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/Favorites.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class Favorites 6 | { 7 | public Guid FavoriteId { get; set; } 8 | public Guid UserId { get; set; } 9 | public Guid RecipeId { get; set; } 10 | public Guid? MenuId { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/IngredientForms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class IngredientForms 7 | { 8 | public Guid IngredientFormId { get; set; } 9 | public Guid IngredientId { get; set; } 10 | public short ConvMultiplier { get; set; } 11 | public float FormAmount { get; set; } 12 | public Units UnitType { get; set; } 13 | public string UnitName { get; set; } 14 | public Units FormUnit { get; set; } 15 | public string FormDisplayName { get; set; } 16 | 17 | public static IngredientForm ToIngredientForm(IngredientForms dtoForm) 18 | { 19 | return new IngredientForm 20 | { 21 | FormId = dtoForm.IngredientFormId, 22 | FormUnitType = dtoForm.UnitType, 23 | ConversionMultiplier = dtoForm.ConvMultiplier, 24 | FormDisplayName = dtoForm.FormDisplayName, 25 | FormUnitName = dtoForm.UnitName, 26 | IngredientId = dtoForm.IngredientId, 27 | FormAmount = new Amount(dtoForm.FormAmount, dtoForm.FormUnit) 28 | }; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/IngredientMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class IngredientMetadata 6 | { 7 | public Guid IngredientMetadataId { get; set; } 8 | public Guid IngredientId { get; set; } 9 | 10 | public bool? HasMeat { get; set; } 11 | public float? CarbsPerUnit { get; set; } 12 | public bool? HasRedMeat { get; set; } 13 | public float? SugarPerUnit { get; set; } 14 | public bool? HasPork { get; set; } 15 | public float? FatPerUnit { get; set; } 16 | public float? SodiumPerUnit { get; set; } 17 | public float? CaloriesPerUnit { get; set; } 18 | public short Spicy { get; set; } 19 | public short Sweet { get; set; } 20 | public bool? HasGluten { get; set; } 21 | public bool? HasAnimal { get; set; } 22 | 23 | public static KitchenPC.Ingredients.IngredientMetadata ToIngredientMetadata(IngredientMetadata metadata) 24 | { 25 | return new KitchenPC.Ingredients.IngredientMetadata 26 | { 27 | HasMeat = metadata.HasMeat, 28 | CarbsPerUnit = metadata.CarbsPerUnit, 29 | HasRedMeat = metadata.HasRedMeat, 30 | SugarPerUnit = metadata.SugarPerUnit, 31 | HasPork = metadata.HasPork, 32 | FatPerUnit = metadata.FatPerUnit, 33 | SodiumPerUnit = metadata.SodiumPerUnit, 34 | CaloriesPerUnit = metadata.CaloriesPerUnit, 35 | Spicy = metadata.Spicy, 36 | Sweet = metadata.Sweet, 37 | HasGluten = metadata.HasGluten, 38 | HasAnimal = metadata.HasAnimal 39 | }; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/Ingredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class Ingredients 7 | { 8 | public Guid IngredientId { get; set; } 9 | public string FoodGroup { get; set; } 10 | public string UsdaId { get; set; } 11 | public string UnitName { get; set; } 12 | public string ManufacturerName { get; set; } 13 | public UnitType ConversionType { get; set; } 14 | public int UnitWeight { get; set; } 15 | public string DisplayName { get; set; } 16 | public string UsdaDesc { get; set; } 17 | 18 | public static Ingredient ToIngredient(Ingredients dtoIngredient, IngredientMetadata metadata = null) 19 | { 20 | return new Ingredient 21 | { 22 | Id = dtoIngredient.IngredientId, 23 | ConversionType = dtoIngredient.ConversionType, 24 | Name = dtoIngredient.DisplayName, 25 | UnitName = dtoIngredient.UnitName, 26 | UnitWeight = dtoIngredient.UnitWeight, 27 | Metadata = (metadata != null ? IngredientMetadata.ToIngredientMetadata(metadata) : null) 28 | }; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/Menus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Menus; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class Menus 7 | { 8 | public Guid MenuId { get; set; } 9 | public Guid UserId { get; set; } 10 | public String Title { get; set; } 11 | public DateTime CreatedDate { get; set; } 12 | 13 | public static Menu ToMenu(Menus dtoMenu) 14 | { 15 | return new Menu 16 | { 17 | Id = dtoMenu.MenuId, 18 | Title = dtoMenu.Title 19 | }; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpAnomalousIngredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class NlpAnomalousIngredients 6 | { 7 | public Guid AnomalousIngredientId { get; set; } 8 | public String Name { get; set; } 9 | public Guid IngredientId { get; set; } 10 | public Guid? WeightFormId { get; set; } 11 | public Guid? VolumeFormId { get; set; } 12 | public Guid? UnitFormId { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpDefaultPairings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class NlpDefaultPairings 6 | { 7 | public virtual Guid DefaultPairingId { get; set; } 8 | public virtual Guid IngredientId { get; set; } 9 | public virtual Guid? WeightFormId { get; set; } 10 | public virtual Guid? VolumeFormId { get; set; } 11 | public virtual Guid? UnitFormId { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpFormSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class NlpFormSynonyms 6 | { 7 | public Guid FormSynonymId { get; set; } 8 | public Guid IngredientId { get; set; } 9 | public Guid FormId { get; set; } 10 | public string Name { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpIngredientSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class NlpIngredientSynonyms 6 | { 7 | public Guid IngredientSynonymId { get; set; } 8 | public Guid IngredientId { get; set; } 9 | public string Alias { get; set; } 10 | public string Prepnote { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpPrepNotes.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Data.DTO 2 | { 3 | public class NlpPrepNotes 4 | { 5 | public string Name { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/NlpUnitSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class NlpUnitSynonyms 6 | { 7 | public Guid UnitSynonymId { get; set; } 8 | public Guid IngredientId { get; set; } 9 | public Guid FormId { get; set; } 10 | public string Name { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/QueuedRecipes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class QueuedRecipes 6 | { 7 | public Guid QueueId { get; set; } 8 | public Guid UserId { get; set; } 9 | public Guid RecipeId { get; set; } 10 | public DateTime QueuedDate { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/RecipeData.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Data.DTO 2 | { 3 | public class RecipeData 4 | { 5 | public Recipes Recipe { get; set; } 6 | public RecipeIngredients[] Ingredients { get; set; } 7 | public RecipeMetadata Metadata { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/RecipeIngredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class RecipeIngredients 6 | { 7 | public Guid RecipeIngredientId { get; set; } 8 | public Guid RecipeId { get; set; } 9 | public Guid IngredientId { get; set; } 10 | public Guid? IngredientFormId { get; set; } 11 | 12 | public Units Unit { get; set; } 13 | public float? QtyLow { get; set; } 14 | public short DisplayOrder { get; set; } 15 | public string PrepNote { get; set; } 16 | public float? Qty { get; set; } 17 | public string Section { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/RecipeMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class RecipeMetadata 7 | { 8 | public Guid RecipeMetadataId { get; set; } 9 | public Guid RecipeId { get; set; } 10 | 11 | public int PhotoRes { get; set; } 12 | public float Commonality { get; set; } 13 | public bool UsdaMatch { get; set; } 14 | 15 | public bool MealBreakfast { get; set; } 16 | public bool MealLunch { get; set; } 17 | public bool MealDinner { get; set; } 18 | public bool MealDessert { get; set; } 19 | 20 | public bool DietNomeat { get; set; } 21 | public bool DietGlutenFree { get; set; } 22 | public bool DietNoRedMeat { get; set; } 23 | public bool DietNoAnimals { get; set; } 24 | public bool DietNoPork { get; set; } 25 | 26 | public short NutritionTotalfat { get; set; } 27 | public short NutritionTotalSodium { get; set; } 28 | public bool NutritionLowSodium { get; set; } 29 | public bool NutritionLowSugar { get; set; } 30 | public bool NutritionLowCalorie { get; set; } 31 | public short NutritionTotalSugar { get; set; } 32 | public short NutritionTotalCalories { get; set; } 33 | public bool NutritionLowFat { get; set; } 34 | public bool NutritionLowCarb { get; set; } 35 | public short NutritionTotalCarbs { get; set; } 36 | 37 | public bool SkillQuick { get; set; } 38 | public bool SkillEasy { get; set; } 39 | public bool SkillCommon { get; set; } 40 | 41 | public short TasteMildToSpicy { get; set; } 42 | public short TasteSavoryToSweet { get; set; } 43 | 44 | public static RecipeTags ToRecipeTags(RecipeMetadata metadata) 45 | { 46 | return 47 | (metadata.DietGlutenFree ? 1 << 0 : 0) + 48 | (metadata.DietNoAnimals ? 1 << 1 : 0) + 49 | (metadata.DietNomeat ? 1 << 2 : 0) + 50 | (metadata.DietNoPork ? 1 << 3 : 0) + 51 | (metadata.DietNoRedMeat ? 1 << 4 : 0) + 52 | (metadata.MealBreakfast ? 1 << 5 : 0) + 53 | (metadata.MealDessert ? 1 << 6 : 0) + 54 | (metadata.MealDinner ? 1 << 7 : 0) + 55 | (metadata.MealLunch ? 1 << 8 : 0) + 56 | (metadata.NutritionLowCalorie ? 1 << 9 : 0) + 57 | (metadata.NutritionLowCarb ? 1 << 10 : 0) + 58 | (metadata.NutritionLowFat ? 1 << 11 : 0) + 59 | (metadata.NutritionLowSodium ? 1 << 12 : 0) + 60 | (metadata.NutritionLowSugar ? 1 << 13 : 0) + 61 | (metadata.SkillCommon ? 1 << 14 : 0) + 62 | (metadata.SkillEasy ? 1 << 15 : 0) + 63 | (metadata.SkillQuick ? 1 << 16 : 0); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/RecipeRatings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class RecipeRatings 6 | { 7 | public Guid RatingId { get; set; } 8 | public Guid UserId { get; set; } 9 | public Guid RecipeId { get; set; } 10 | public Int16 Rating { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/Recipes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Recipes; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class Recipes 7 | { 8 | public Guid RecipeId { get; set; } 9 | public short? CookTime { get; set; } 10 | public string Steps { get; set; } 11 | public short? PrepTime { get; set; } 12 | public short Rating { get; set; } 13 | public string Description { get; set; } 14 | public string Title { get; set; } 15 | public bool Hidden { get; set; } 16 | public string Credit { get; set; } 17 | public string CreditUrl { get; set; } 18 | public DateTime DateEntered { get; set; } 19 | public short ServingSize { get; set; } 20 | public string ImageUrl { get; set; } 21 | 22 | public static RecipeBrief ToRecipeBrief(Recipes dtoRecipe) 23 | { 24 | return new RecipeBrief 25 | { 26 | Id = dtoRecipe.RecipeId, 27 | ImageUrl = dtoRecipe.ImageUrl, 28 | AvgRating = dtoRecipe.Rating, 29 | CookTime = dtoRecipe.CookTime, 30 | PrepTime = dtoRecipe.PrepTime, 31 | Description = dtoRecipe.Description, 32 | Title = dtoRecipe.Title 33 | }; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/ShoppingListItems.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Data.DTO 4 | { 5 | public class ShoppingListItems 6 | { 7 | public Guid ItemId { get; set; } 8 | public String Raw { get; set; } 9 | public float? Qty { get; set; } 10 | public Units? Unit { get; set; } 11 | public Guid UserId { get; set; } 12 | public Guid? IngredientId { get; set; } 13 | public Guid? RecipeId { get; set; } 14 | public Guid? ShoppingListId { get; set; } 15 | public bool CrossedOut { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/DTO/ShoppingLists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.ShoppingLists; 3 | 4 | namespace KitchenPC.Data.DTO 5 | { 6 | public class ShoppingLists 7 | { 8 | public Guid ShoppingListId { get; set; } 9 | public Guid UserId { get; set; } 10 | public String Title { get; set; } 11 | 12 | public static ShoppingList ToShoppingList(ShoppingLists dtoList) 13 | { 14 | return new ShoppingList 15 | { 16 | Id = dtoList.ShoppingListId, 17 | Title = dtoList.Title 18 | }; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/IProvisionSource.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Data 2 | { 3 | /// Represents a source in which a KitchenPC Context can be provisioned from. 4 | public interface IProvisionSource 5 | { 6 | DataStore Export(); 7 | } 8 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/IProvisionTarget.cs: -------------------------------------------------------------------------------- 1 | using KitchenPC.Data; 2 | 3 | namespace KitchenPC.Provisioning 4 | { 5 | /// Represents a target which can be provisioned based on data exported from an IProvisionSource. 6 | public interface IProvisionTarget 7 | { 8 | void Import(IProvisionSource source); 9 | void InitializeStore(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/Provisioning/IProvisioner.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using KitchenPC.Data.DTO; 3 | 4 | namespace KitchenPC.Data 5 | { 6 | public interface IProvisioner 7 | { 8 | // Core Data (Immutable) 9 | IngredientForms[] IngredientForms(); 10 | IngredientMetadata[] IngredientMetadata(); 11 | DTO.Ingredients[] Ingredients(); 12 | NlpAnomalousIngredients[] NlpAnomalousIngredients(); 13 | NlpDefaultPairings[] NlpDefaultPairings(); 14 | NlpFormSynonyms[] NlpFormSynonyms(); 15 | NlpIngredientSynonyms[] NlpIngredientSynonyms(); 16 | NlpPrepNotes[] NlpPrepNotes(); 17 | NlpUnitSynonyms[] NlpUnitSynonyms(); 18 | 19 | // Recipe Data 20 | List Recipes(); 21 | List RecipeMetadata(); 22 | List RecipeIngredients(); 23 | 24 | // User Data 25 | List Favorites(); 26 | List Menus(); 27 | List QueuedRecipes(); 28 | List RecipeRatings(); 29 | List ShoppingLists(); 30 | List ShoppingListItems(); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Core/Recipes/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Recipes 2 | { 3 | public enum MealFilter 4 | { 5 | All, 6 | Breakfast, 7 | Lunch, 8 | Dinner, 9 | Dessert 10 | } 11 | 12 | public enum Rating 13 | { 14 | None = 0, 15 | 16 | OneStar = 1, 17 | TwoStars = 2, 18 | ThreeStars = 3, 19 | FourStars = 4, 20 | FiveStars = 5 21 | } 22 | } -------------------------------------------------------------------------------- /src/Core/Recipes/ReadRecipeOptions.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.Recipes 2 | { 3 | public class ReadRecipeOptions 4 | { 5 | public bool ReturnCommentCount; 6 | public bool ReturnUserRating; 7 | public bool ReturnCookbookStatus; 8 | public bool ReturnMethod; 9 | public bool ReturnPermalink; 10 | 11 | static readonly ReadRecipeOptions none = new ReadRecipeOptions(); 12 | static readonly ReadRecipeOptions methodonly = new ReadRecipeOptions {ReturnMethod = true}; 13 | 14 | public static ReadRecipeOptions None 15 | { 16 | get 17 | { 18 | return none; 19 | } 20 | } 21 | 22 | public static ReadRecipeOptions MethodOnly 23 | { 24 | get 25 | { 26 | return methodonly; 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Core/Recipes/RecipeBrief.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Recipes 4 | { 5 | public class RecipeBrief 6 | { 7 | Uri recipeimg; 8 | 9 | public Guid Id; 10 | public Guid OwnerId; 11 | public String Permalink; 12 | public String Title; 13 | public String Description; 14 | public String Author; 15 | public short? PrepTime; 16 | public short? CookTime; 17 | public short AvgRating = 0; 18 | 19 | public String ImageUrl 20 | { 21 | get 22 | { 23 | return (recipeimg == null ? "/Images/img_placeholder.png" : recipeimg.ToString()); 24 | } 25 | 26 | set 27 | { 28 | if (String.IsNullOrEmpty(value)) 29 | { 30 | recipeimg = null; 31 | return; 32 | } 33 | 34 | //UriBuilder builder = new UriBuilder(baseUri); 35 | var builder = new UriBuilder(); 36 | builder.Path = "Thumb_" + value; 37 | recipeimg = builder.Uri; 38 | } 39 | } 40 | 41 | public RecipeBrief() 42 | { 43 | } 44 | 45 | public RecipeBrief(Recipe r) 46 | { 47 | this.Id = r.Id; 48 | this.OwnerId = r.OwnerId; 49 | this.Title = r.Title; 50 | this.Description = r.Description; 51 | this.ImageUrl = r.ImageUrl; 52 | this.Author = r.OwnerAlias; 53 | this.PrepTime = r.PrepTime; 54 | this.CookTime = r.CookTime; 55 | this.AvgRating = r.AvgRating; 56 | } 57 | 58 | public override string ToString() 59 | { 60 | return String.Format("{0} ({1})", Title, Id); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/Core/Recipes/RecipeResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Recipes 4 | { 5 | public class RecipeResult 6 | { 7 | public bool RecipeCreated; 8 | public bool RecipeUpdated; 9 | 10 | public Guid? NewRecipeId; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/Recipes/SearchResults.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.Recipes 4 | { 5 | public class SearchResults 6 | { 7 | public RecipeBrief[] Briefs; 8 | 9 | public Int64 TotalCount { get; set; } 10 | 11 | public SearchResults(RecipeBrief[] briefs, Int64 total) 12 | { 13 | this.Briefs = briefs; 14 | this.TotalCount = total; 15 | } 16 | 17 | public SearchResults() 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.ShoppingLists 2 | { 3 | public enum ShoppingListUpdateType 4 | { 5 | AddItem, 6 | RemoveItem, 7 | ModifyItem 8 | }; 9 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/GetShoppingListOptions.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.ShoppingLists 2 | { 3 | public class GetShoppingListOptions 4 | { 5 | public bool LoadItems; 6 | 7 | static readonly GetShoppingListOptions none = new GetShoppingListOptions(); 8 | static readonly GetShoppingListOptions loaded = new GetShoppingListOptions {LoadItems = true}; 9 | 10 | public static GetShoppingListOptions None 11 | { 12 | get 13 | { 14 | return none; 15 | } 16 | } 17 | 18 | public static GetShoppingListOptions WithItems 19 | { 20 | get 21 | { 22 | return loaded; 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/IShoppingListSource.cs: -------------------------------------------------------------------------------- 1 | namespace KitchenPC.ShoppingLists 2 | { 3 | public interface IShoppingListSource 4 | { 5 | ShoppingListItem GetItem(); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/ShoppingListItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.ShoppingLists 6 | { 7 | public class ShoppingListItem : IngredientAggregation 8 | { 9 | public string Raw { get; set; } 10 | public Guid? Id { get; set; } 11 | public RecipeBrief Recipe { get; set; } 12 | public bool CrossedOut { get; set; } 13 | 14 | public static ShoppingListItem FromId(Guid id) 15 | { 16 | return new ShoppingListItem(id); 17 | } 18 | 19 | public ShoppingListItem(Guid id) : base(null) 20 | { 21 | Id = id; 22 | } 23 | 24 | public ShoppingListItem(string raw) : base(null) 25 | { 26 | if (String.IsNullOrWhiteSpace(raw)) 27 | throw new ArgumentException("Shopping list item cannot be blank."); 28 | 29 | Raw = raw; 30 | } 31 | 32 | public ShoppingListItem(Ingredient ingredient) : base(ingredient) 33 | { 34 | } 35 | 36 | public override IngredientAggregation AddUsage(IngredientUsage usage) 37 | { 38 | if (Ingredient == null) 39 | throw new ArgumentException("Cannot add usage to a non-resolved shopping list item. Create a new shopping list based on an IngredientUsage."); 40 | 41 | return base.AddUsage(usage); 42 | } 43 | 44 | public override ShoppingListItem GetItem() 45 | { 46 | return this; 47 | } 48 | 49 | public override string ToString() 50 | { 51 | return (!String.IsNullOrEmpty(Raw) ? Raw : base.ToString()); 52 | } 53 | 54 | public static implicit operator ShoppingListItem(string s) 55 | { 56 | return new ShoppingListItem(s); 57 | } 58 | 59 | public static implicit operator String(ShoppingListItem i) 60 | { 61 | return i.ToString(); 62 | } 63 | 64 | public override bool Equals(object obj) 65 | { 66 | var item = obj as ShoppingListItem; 67 | if (item == null) 68 | return false; 69 | 70 | if (this.Ingredient != null && item.Ingredient != null) // If they both represent an ingredient, compare by ingredient 71 | return this.Ingredient.Equals(item.Ingredient); 72 | 73 | // Compare by Raw string 74 | return String.Equals(this.Raw, item.Raw, StringComparison.InvariantCulture); 75 | } 76 | 77 | public override int GetHashCode() 78 | { 79 | return Ingredient != null ? Ingredient.Id.GetHashCode() : Raw.GetHashCode(); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/ShoppingListModification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.ShoppingLists 4 | { 5 | public class ShoppingListModification 6 | { 7 | public Guid ModifiedItemId { get; private set; } 8 | public Amount NewAmount { get; private set; } 9 | public Boolean? CrossOut { get; private set; } 10 | 11 | public ShoppingListModification(Guid itemId, Amount newAmount, Boolean? crossout) 12 | { 13 | ModifiedItemId = itemId; 14 | NewAmount = newAmount; 15 | CrossOut = crossout; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/ShoppingListResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC.ShoppingLists 4 | { 5 | public class ShoppingListResult 6 | { 7 | public Guid? NewShoppingListId; 8 | public ShoppingList List; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/ShoppingLists/ShoppingListUpdateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.ShoppingLists 6 | { 7 | public class ShoppingListUpdateCommand 8 | { 9 | public ShoppingListUpdateType Command { get; set; } 10 | 11 | public Recipe NewRecipe { get; set; } 12 | public Ingredient NewIngredient { get; set; } 13 | public IngredientUsage NewUsage { get; set; } 14 | public String NewRaw { get; set; } 15 | 16 | public Guid? RemoveItem { get; set; } 17 | public ShoppingListModification ModifyItem { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/UnitConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace KitchenPC 4 | { 5 | public static class UnitConverter 6 | { 7 | static readonly Single[,] ConversionMatrix = 8 | { 9 | {1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, //Unit 10 | {-1, 1.0f, 3.0f, 6.0f, 48.0f, 96.0f, 192.0f, 768.0f, -1, -1, -1}, //Teaspoon 11 | {-1, 1/3.0f, 1, 2.0f, 16.0f, 32.0f, 64.0f, 256.0f, -1, -1, -1}, //Tablespoon 12 | {-1, 1/6.0f, 0.5f, 1, 8.0f, 16.0f, 32.0f, 128.0f, -1, -1, -1}, //FluidOunce 13 | {-1, 1/48.0f, 1/16.0f, 0.125f, 1, 2.0f, 4.0f, 16.0f, -1, -1, -1}, //Cup 14 | {-1, 1/96.0f, 1/32.0f, 1/16.0f, 0.5f, 1, 2.0f, 8.0f, -1, -1, -1}, //Pint 15 | {-1, 1/192.0f, 1/64.0f, 1/32.0f, 0.25f, 0.5f, 1, 4.0f, -1, -1, -1}, //Quart 16 | {-1, 1/768.0f, 1/256.0f, 1/128.0f, 1/16.0f, 0.125f, 0.25f, 1, -1, -1, -1}, //Gallon 17 | {-1, -1, -1, -1, -1, -1, -1, -1, 1, 28.3495231f, 453.59237f}, //Gram 18 | {-1, -1, -1, -1, -1, -1, -1, -1, 1/28.3495231f, 1, 16.0f}, //Ounce 19 | {-1, -1, -1, -1, -1, -1, -1, -1, 1/453.59237f, 0.0625f, 1} //Pound 20 | }; 21 | 22 | public static bool CanConvert(Units fromUnit, Units toUnit) 23 | { 24 | return (ConversionMatrix[(int) toUnit, (int) fromUnit] != -1); 25 | } 26 | 27 | public static Single Convert(Single amount, Units fromUnit, Units toUnit) 28 | { 29 | if (fromUnit == toUnit) 30 | return amount; 31 | 32 | if (ConversionMatrix[(int) toUnit, (int) fromUnit] == -1) 33 | throw new ArgumentException("Cannot convert from unit " + Unit.GetSingular(fromUnit) + " to unit " + Unit.GetSingular(toUnit)); 34 | 35 | var coefficient = ConversionMatrix[(int) toUnit, (int) fromUnit]; 36 | return amount*coefficient; 37 | } 38 | 39 | public static Amount Convert(Amount amount, Units toUnit) 40 | { 41 | var ret = new Amount(); 42 | ret.Unit = toUnit; 43 | ret.SizeLow = amount.SizeLow.HasValue ? (float?) Convert(amount.SizeLow.Value, amount.Unit, toUnit) : null; 44 | ret.SizeHigh = Convert(amount.SizeHigh, amount.Unit, toUnit); 45 | 46 | return ret; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/DB/DatabaseAdapterBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentNHibernate.Cfg.Db; 4 | using FluentNHibernate.Conventions; 5 | using KitchenPC.Context; 6 | 7 | namespace KitchenPC.DB 8 | { 9 | public class DatabaseAdapterBuilder : IConfigurationBuilder 10 | { 11 | readonly DatabaseAdapter adapter; 12 | 13 | public DatabaseAdapterBuilder(DatabaseAdapter adapter) 14 | { 15 | this.adapter = adapter; 16 | } 17 | 18 | public DatabaseAdapterBuilder DatabaseConfiguration(IPersistenceConfigurer config) 19 | { 20 | adapter.DatabaseConfiguration = config; 21 | return this; 22 | } 23 | 24 | public DatabaseAdapterBuilder AddConvention(IConvention convention) 25 | { 26 | if (adapter.DatabaseConventions == null) 27 | adapter.DatabaseConventions = new List(); 28 | 29 | adapter.DatabaseConventions.Add(convention); 30 | 31 | return this; 32 | } 33 | 34 | public DatabaseAdapterBuilder SearchProvider(Func createProvider) where T : ISearchProvider 35 | { 36 | adapter.SearchProvider = createProvider(adapter); 37 | return this; 38 | } 39 | 40 | public DatabaseAdapter Create() 41 | { 42 | return adapter; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/DB/EnumMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using FluentNHibernate.Conventions; 3 | using FluentNHibernate.Conventions.Helpers; 4 | using FluentNHibernate.Mapping; 5 | using NHibernate.SqlTypes; 6 | using NHibernate.Type; 7 | 8 | namespace KitchenPC.DB 9 | { 10 | public class EnumMapper : EnumStringType 11 | { 12 | public override SqlType SqlType 13 | { 14 | get 15 | { 16 | return new SqlType(DbType.Object); 17 | } 18 | } 19 | 20 | public static IPropertyConvention Convention 21 | { 22 | get 23 | { 24 | return ConventionBuilder.Property.When( 25 | c => c.Expect(x => x.Type == typeof (GenericEnumMapper)), 26 | x => 27 | { 28 | x.CustomType>(); 29 | x.CustomSqlType((typeof (T).Name)); 30 | }); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/DB/Models/Favorites.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class Favorites 7 | { 8 | public virtual Guid FavoriteId { get; set; } 9 | public virtual Guid UserId { get; set; } 10 | public virtual Recipes Recipe { get; set; } 11 | public virtual Menus Menu { get; set; } 12 | } 13 | 14 | public class FavoritesMap : ClassMap 15 | { 16 | public FavoritesMap() 17 | { 18 | Id(x => x.FavoriteId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.UserId).Not.Nullable().Index("IDX_Favorites_UserId"); 23 | 24 | References(x => x.Recipe).Not.Nullable().Index("IDX_Favorites_RecipeId"); 25 | References(x => x.Menu); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/IngredientForms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | using KitchenPC.Ingredients; 4 | 5 | namespace KitchenPC.DB.Models 6 | { 7 | public class IngredientForms 8 | { 9 | public virtual Guid IngredientFormId { get; set; } 10 | public virtual Ingredients Ingredient { get; set; } 11 | 12 | public virtual short ConvMultiplier { get; set; } 13 | public virtual float FormAmount { get; set; } 14 | public virtual Units UnitType { get; set; } 15 | public virtual string UnitName { get; set; } 16 | public virtual Units FormUnit { get; set; } 17 | public virtual string FormDisplayName { get; set; } 18 | 19 | public static IngredientForms FromId(Guid id) 20 | { 21 | return new IngredientForms 22 | { 23 | IngredientFormId = id 24 | }; 25 | } 26 | 27 | public virtual IngredientForm AsIngredientForm() 28 | { 29 | return new IngredientForm 30 | { 31 | FormId = IngredientFormId, 32 | FormUnitType = UnitType, 33 | ConversionMultiplier = ConvMultiplier, 34 | FormDisplayName = FormDisplayName, 35 | FormUnitName = UnitName, 36 | IngredientId = Ingredient.IngredientId, 37 | FormAmount = new Amount(FormAmount, FormUnit) 38 | }; 39 | } 40 | } 41 | 42 | public class IngredientFormsMap : ClassMap 43 | { 44 | public IngredientFormsMap() 45 | { 46 | Id(x => x.IngredientFormId) 47 | .GeneratedBy.GuidComb() 48 | .UnsavedValue(Guid.Empty); 49 | 50 | Map(x => x.ConvMultiplier).Not.Nullable(); 51 | Map(x => x.FormAmount).Not.Nullable(); 52 | Map(x => x.UnitType).Not.Nullable(); 53 | Map(x => x.UnitName).Length(50); 54 | Map(x => x.FormUnit).Not.Nullable(); 55 | Map(x => x.FormDisplayName).Length(200).UniqueKey("UniqueIngredientForm"); 56 | 57 | References(x => x.Ingredient).Not.Nullable().UniqueKey("UniqueIngredientForm"); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/DB/Models/IngredientMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class IngredientMetadata 7 | { 8 | public virtual Guid IngredientMetadataId { get; set; } 9 | public virtual Ingredients Ingredient { get; set; } 10 | 11 | public virtual bool? HasMeat { get; set; } 12 | public virtual float? CarbsPerUnit { get; set; } 13 | public virtual bool? HasRedMeat { get; set; } 14 | public virtual float? SugarPerUnit { get; set; } 15 | public virtual bool? HasPork { get; set; } 16 | public virtual float? FatPerUnit { get; set; } 17 | public virtual float? SodiumPerUnit { get; set; } 18 | public virtual float? CaloriesPerUnit { get; set; } 19 | public virtual short Spicy { get; set; } 20 | public virtual short Sweet { get; set; } 21 | public virtual bool? HasGluten { get; set; } 22 | public virtual bool? HasAnimal { get; set; } 23 | 24 | public virtual KitchenPC.Ingredients.IngredientMetadata AsIngredientMetadata() 25 | { 26 | return new KitchenPC.Ingredients.IngredientMetadata 27 | { 28 | HasMeat = HasMeat, 29 | CarbsPerUnit = CarbsPerUnit, 30 | HasRedMeat = HasRedMeat, 31 | SugarPerUnit = SugarPerUnit, 32 | HasPork = HasPork, 33 | FatPerUnit = FatPerUnit, 34 | SodiumPerUnit = SodiumPerUnit, 35 | CaloriesPerUnit = CaloriesPerUnit, 36 | Spicy = Spicy, 37 | Sweet = Sweet, 38 | HasGluten = HasGluten, 39 | HasAnimal = HasAnimal 40 | }; 41 | } 42 | } 43 | 44 | public class IngredientMetadataMap : ClassMap 45 | { 46 | public IngredientMetadataMap() 47 | { 48 | Id(x => x.IngredientMetadataId) 49 | .GeneratedBy.GuidComb() 50 | .UnsavedValue(Guid.Empty); 51 | 52 | Map(x => x.HasMeat); 53 | Map(x => x.CarbsPerUnit); 54 | Map(x => x.HasRedMeat); 55 | Map(x => x.SugarPerUnit); 56 | Map(x => x.HasPork); 57 | Map(x => x.FatPerUnit); 58 | Map(x => x.SodiumPerUnit); 59 | Map(x => x.CaloriesPerUnit); 60 | Map(x => x.Spicy).Not.Nullable(); 61 | Map(x => x.Sweet).Not.Nullable(); 62 | Map(x => x.HasGluten); 63 | Map(x => x.HasAnimal); 64 | 65 | References(x => x.Ingredient).Not.Nullable().Unique(); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/DB/Models/Ingredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentNHibernate.Mapping; 4 | using KitchenPC.Ingredients; 5 | 6 | namespace KitchenPC.DB.Models 7 | { 8 | public class Ingredients 9 | { 10 | public virtual Guid IngredientId { get; set; } 11 | public virtual string FoodGroup { get; set; } 12 | public virtual string UsdaId { get; set; } 13 | public virtual string UnitName { get; set; } 14 | public virtual string ManufacturerName { get; set; } 15 | public virtual UnitType ConversionType { get; set; } 16 | public virtual int UnitWeight { get; set; } 17 | public virtual string DisplayName { get; set; } 18 | public virtual string UsdaDesc { get; set; } 19 | 20 | public virtual IList Forms { get; set; } 21 | public virtual IngredientMetadata Metadata { get; set; } 22 | 23 | public virtual Ingredient AsIngredient() 24 | { 25 | return new Ingredient 26 | { 27 | Id = IngredientId, 28 | ConversionType = ConversionType, 29 | Name = DisplayName, 30 | UnitName = UnitName, 31 | UnitWeight = UnitWeight, 32 | Metadata = (Metadata != null ? Metadata.AsIngredientMetadata() : null) 33 | }; 34 | } 35 | 36 | public static Ingredients FromId(Guid id) 37 | { 38 | return new Ingredients 39 | { 40 | IngredientId = id 41 | }; 42 | } 43 | } 44 | 45 | public class IngredientsMap : ClassMap 46 | { 47 | public IngredientsMap() 48 | { 49 | Id(x => x.IngredientId) 50 | .GeneratedBy.GuidComb() 51 | .UnsavedValue(Guid.Empty); 52 | 53 | Map(x => x.FoodGroup).Length(4); 54 | Map(x => x.UsdaId).Length(5); 55 | Map(x => x.UnitName).Length(50); 56 | Map(x => x.ManufacturerName).Length(65); 57 | Map(x => x.ConversionType).Not.Nullable(); 58 | Map(x => x.UnitWeight).Not.Nullable().Default("0"); 59 | Map(x => x.DisplayName).Not.Nullable().Length(200).Unique().Index("IDX_Ingredients_DisplayName"); 60 | Map(x => x.UsdaDesc).Length(200); 61 | 62 | HasMany(x => x.Forms).KeyColumn("IngredientId"); 63 | HasOne(x => x.Metadata).PropertyRef(x => x.Ingredient).Cascade.All(); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/DB/Models/Menus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentNHibernate.Mapping; 4 | using KitchenPC.Menus; 5 | 6 | namespace KitchenPC.DB.Models 7 | { 8 | public class Menus 9 | { 10 | public virtual Guid MenuId { get; set; } 11 | public virtual Guid UserId { get; set; } 12 | public virtual String Title { get; set; } 13 | public virtual DateTime CreatedDate { get; set; } 14 | 15 | public virtual IList Recipes { get; set; } 16 | 17 | public static Menus FromId(Guid id) 18 | { 19 | return new Menus 20 | { 21 | MenuId = id 22 | }; 23 | } 24 | 25 | public virtual Menu AsMenu() 26 | { 27 | return new Menu 28 | { 29 | Id = MenuId, 30 | Title = Title, 31 | }; 32 | } 33 | 34 | public static bool operator !=(Menu menu, Menus dbMenu) 35 | { 36 | return !(menu == dbMenu); 37 | } 38 | 39 | public static bool operator ==(Menu menu, Menus dbMenu) 40 | { 41 | if (dbMenu == null) 42 | { 43 | return !menu.Id.HasValue; 44 | } 45 | 46 | return menu.Id == dbMenu.MenuId; 47 | } 48 | 49 | public override bool Equals(object obj) 50 | { 51 | if (false == (obj is Menus)) 52 | return false; 53 | 54 | var menu = (Menus) obj; 55 | return MenuId.Equals(menu.MenuId); 56 | } 57 | 58 | public override int GetHashCode() 59 | { 60 | return MenuId.GetHashCode(); 61 | } 62 | } 63 | 64 | public class MenusMap : ClassMap 65 | { 66 | public MenusMap() 67 | { 68 | Id(x => x.MenuId) 69 | .GeneratedBy.GuidComb() 70 | .UnsavedValue(Guid.Empty); 71 | 72 | Map(x => x.UserId).Not.Nullable().Index("IDX_Menus_UserId").UniqueKey("UserTitle"); 73 | Map(x => x.Title).Not.Nullable().UniqueKey("UserTitle"); 74 | Map(x => x.CreatedDate).Not.Nullable(); 75 | 76 | HasMany(x => x.Recipes) 77 | .KeyColumn("MenuId") 78 | .Cascade.Delete(); // If Menu is deleted, delete all the Favorites that reference this menu 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpAnomalousIngredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class NlpAnomalousIngredients 7 | { 8 | public virtual Guid AnomalousIngredientId { get; set; } 9 | public virtual String Name { get; set; } 10 | public virtual Ingredients Ingredient { get; set; } 11 | public virtual IngredientForms WeightForm { get; set; } 12 | public virtual IngredientForms VolumeForm { get; set; } 13 | public virtual IngredientForms UnitForm { get; set; } 14 | } 15 | 16 | public class NlpAnomalousIngredientsMap : ClassMap 17 | { 18 | public NlpAnomalousIngredientsMap() 19 | { 20 | Id(x => x.AnomalousIngredientId) 21 | .GeneratedBy.GuidComb() 22 | .UnsavedValue(Guid.Empty); 23 | 24 | Map(x => x.Name).Not.Nullable().Length(100).Unique(); 25 | 26 | References(x => x.Ingredient).Not.Nullable(); 27 | References(x => x.WeightForm); 28 | References(x => x.VolumeForm); 29 | References(x => x.UnitForm); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpDefaultPairings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class NlpDefaultPairings 7 | { 8 | public virtual Guid DefaultPairingId { get; set; } 9 | public virtual Ingredients Ingredient { get; set; } 10 | public virtual IngredientForms WeightForm { get; set; } 11 | public virtual IngredientForms VolumeForm { get; set; } 12 | public virtual IngredientForms UnitForm { get; set; } 13 | } 14 | 15 | public class NlpDefaultPairingsMap : ClassMap 16 | { 17 | public NlpDefaultPairingsMap() 18 | { 19 | Id(x => x.DefaultPairingId) 20 | .GeneratedBy.GuidComb() 21 | .UnsavedValue(Guid.Empty); 22 | 23 | References(x => x.Ingredient).Unique().Not.Nullable(); 24 | References(x => x.WeightForm); 25 | References(x => x.VolumeForm); 26 | References(x => x.UnitForm); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpFormSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class NlpFormSynonyms 7 | { 8 | public virtual Guid FormSynonymId { get; set; } 9 | public virtual Ingredients Ingredient { get; set; } 10 | public virtual IngredientForms Form { get; set; } 11 | public virtual string Name { get; set; } 12 | } 13 | 14 | public class NlpFormSynonymsMap : ClassMap 15 | { 16 | public NlpFormSynonymsMap() 17 | { 18 | Id(x => x.FormSynonymId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.Name).Length(50).UniqueKey("FormName"); 23 | 24 | References(x => x.Ingredient).Not.Nullable().UniqueKey("FormName"); 25 | References(x => x.Form).Not.Nullable(); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpIngredientSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class NlpIngredientSynonyms 7 | { 8 | public virtual Guid IngredientSynonymId { get; set; } 9 | public virtual Ingredients Ingredient { get; set; } 10 | public virtual string Alias { get; set; } 11 | public virtual string Prepnote { get; set; } 12 | } 13 | 14 | public class NlpIngredientSynonymsMap : ClassMap 15 | { 16 | public NlpIngredientSynonymsMap() 17 | { 18 | Id(x => x.IngredientSynonymId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.Alias).Length(200).Unique(); 23 | Map(x => x.Prepnote).Length(50); 24 | 25 | References(x => x.Ingredient).Not.Nullable(); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpPrepNotes.cs: -------------------------------------------------------------------------------- 1 | using FluentNHibernate.Mapping; 2 | 3 | namespace KitchenPC.DB.Models 4 | { 5 | public class NlpPrepNotes 6 | { 7 | public virtual string Name { get; set; } 8 | } 9 | 10 | public class NlpPrepNotesMap : ClassMap 11 | { 12 | public NlpPrepNotesMap() 13 | { 14 | Id(x => x.Name).Length(50); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/DB/Models/NlpUnitSynonyms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class NlpUnitSynonyms 7 | { 8 | public virtual Guid UnitSynonymId { get; set; } 9 | public virtual Ingredients Ingredient { get; set; } 10 | public virtual IngredientForms Form { get; set; } 11 | public virtual string Name { get; set; } 12 | } 13 | 14 | public class NlpUnitSynonymsMap : ClassMap 15 | { 16 | public NlpUnitSynonymsMap() 17 | { 18 | Id(x => x.UnitSynonymId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.Name).Length(50).UniqueKey("UniquePair"); 23 | 24 | References(x => x.Ingredient).Not.Nullable().UniqueKey("UniquePair"); 25 | References(x => x.Form).Not.Nullable(); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/QueuedRecipes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class QueuedRecipes 7 | { 8 | public virtual Guid QueueId { get; set; } 9 | public virtual Guid UserId { get; set; } 10 | public virtual Recipes Recipe { get; set; } 11 | public virtual DateTime QueuedDate { get; set; } 12 | } 13 | 14 | public class QueuedRecipesMap : ClassMap 15 | { 16 | public QueuedRecipesMap() 17 | { 18 | Id(x => x.QueueId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.UserId).Not.Nullable().Index("IDX_QueuedRecipes_UserId").UniqueKey("UniqueRecipe"); 23 | Map(x => x.QueuedDate).Not.Nullable(); 24 | 25 | References(x => x.Recipe).Not.Nullable().UniqueKey("UniqueRecipe"); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/RecipeIngredients.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class RecipeIngredients 7 | { 8 | public virtual Guid RecipeIngredientId { get; set; } 9 | public virtual Recipes Recipe { get; set; } 10 | public virtual Ingredients Ingredient { get; set; } 11 | public virtual IngredientForms IngredientForm { get; set; } 12 | 13 | public virtual Units Unit { get; set; } 14 | public virtual float? QtyLow { get; set; } 15 | public virtual short DisplayOrder { get; set; } 16 | public virtual string PrepNote { get; set; } 17 | public virtual float? Qty { get; set; } 18 | public virtual string Section { get; set; } 19 | } 20 | 21 | public class RecipeIngredientsMap : ClassMap 22 | { 23 | public RecipeIngredientsMap() 24 | { 25 | Id(x => x.RecipeIngredientId) 26 | .GeneratedBy.GuidComb() 27 | .UnsavedValue(Guid.Empty); 28 | 29 | Map(x => x.Unit).Not.Nullable(); 30 | Map(x => x.QtyLow); 31 | Map(x => x.DisplayOrder).Not.Nullable(); 32 | Map(x => x.PrepNote).Length(50); 33 | Map(x => x.Qty); 34 | Map(x => x.Section).Length(50); 35 | 36 | References(x => x.Recipe).Column("RecipeId").Not.Nullable().Index("IDX_RecipeIngredients_RecipeId"); 37 | References(x => x.Ingredient).Column("IngredientId").Not.Nullable().Index("IDX_RecipeIngredients_IngredientId"); 38 | References(x => x.IngredientForm).Column("IngredientFormId"); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DB/Models/RecipeRatings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FluentNHibernate.Mapping; 3 | 4 | namespace KitchenPC.DB.Models 5 | { 6 | public class RecipeRatings 7 | { 8 | public virtual Guid RatingId { get; set; } 9 | public virtual Guid UserId { get; set; } 10 | public virtual Recipes Recipe { get; set; } 11 | public virtual Int16 Rating { get; set; } 12 | } 13 | 14 | public class RecipeRatingsMap : ClassMap 15 | { 16 | public RecipeRatingsMap() 17 | { 18 | Id(x => x.RatingId) 19 | .GeneratedBy.GuidComb() 20 | .UnsavedValue(Guid.Empty); 21 | 22 | Map(x => x.UserId).Not.Nullable().Index("IDX_RecipeRatings_UserId").UniqueKey("UserRating"); 23 | Map(x => x.Rating).Not.Nullable(); 24 | 25 | References(x => x.Recipe).Not.Nullable().Index("IDX_RecipeRatings_RecipeId").UniqueKey("UserRating"); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/DB/Models/Recipes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentNHibernate.Mapping; 4 | using KitchenPC.Recipes; 5 | 6 | namespace KitchenPC.DB.Models 7 | { 8 | public class Recipes 9 | { 10 | public virtual Guid RecipeId { get; set; } 11 | public virtual short? CookTime { get; set; } 12 | public virtual string Steps { get; set; } 13 | public virtual short? PrepTime { get; set; } 14 | public virtual short Rating { get; set; } 15 | public virtual string Description { get; set; } 16 | public virtual string Title { get; set; } 17 | public virtual bool Hidden { get; set; } 18 | public virtual string Credit { get; set; } 19 | public virtual string CreditUrl { get; set; } 20 | public virtual DateTime DateEntered { get; set; } 21 | public virtual short ServingSize { get; set; } 22 | public virtual string ImageUrl { get; set; } 23 | 24 | public virtual IList Ingredients { get; set; } 25 | public virtual RecipeMetadata RecipeMetadata { get; set; } 26 | 27 | public virtual RecipeBrief AsRecipeBrief() 28 | { 29 | return new RecipeBrief 30 | { 31 | Id = RecipeId, 32 | ImageUrl = ImageUrl, 33 | AvgRating = Rating, 34 | CookTime = CookTime, 35 | PrepTime = PrepTime, 36 | Description = Description, 37 | Title = Title 38 | }; 39 | } 40 | 41 | public static Recipes FromId(Guid id) 42 | { 43 | return new Recipes 44 | { 45 | RecipeId = id 46 | }; 47 | } 48 | } 49 | 50 | public class RecipesMap : ClassMap 51 | { 52 | public RecipesMap() 53 | { 54 | Id(x => x.RecipeId) 55 | .GeneratedBy.GuidComb() 56 | .UnsavedValue(Guid.Empty); 57 | 58 | Map(x => x.CookTime).Index("IDX_Recipes_Cooktime"); 59 | Map(x => x.Steps).Length(10000); 60 | Map(x => x.PrepTime).Index("IDX_Recipes_Preptime"); 61 | Map(x => x.Rating).Not.Nullable().Index("IDX_Recipes_Rating"); 62 | Map(x => x.Description).Length(512); 63 | Map(x => x.Title).Not.Nullable().Length(100); 64 | Map(x => x.Hidden).Not.Nullable().Index("IDX_Recipes_Hidden"); 65 | Map(x => x.Credit).Length(100); 66 | Map(x => x.CreditUrl).Length(1024); 67 | Map(x => x.DateEntered).Not.Nullable(); 68 | Map(x => x.ServingSize).Not.Nullable().Check("ServingSize > 0"); 69 | Map(x => x.ImageUrl).Length(100); 70 | 71 | HasMany(x => x.Ingredients).KeyColumn("RecipeId"); 72 | HasOne(x => x.RecipeMetadata).PropertyRef(x => x.Recipe).Cascade.All(); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/DB/Models/ShoppingLists.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FluentNHibernate.Mapping; 4 | using KitchenPC.ShoppingLists; 5 | 6 | namespace KitchenPC.DB.Models 7 | { 8 | public class ShoppingLists 9 | { 10 | public virtual Guid ShoppingListId { get; set; } 11 | public virtual Guid UserId { get; set; } 12 | public virtual String Title { get; set; } 13 | 14 | public virtual IList Items { get; set; } 15 | 16 | public static ShoppingLists FromId(Guid id) 17 | { 18 | return new ShoppingLists 19 | { 20 | ShoppingListId = id 21 | }; 22 | } 23 | 24 | public virtual ShoppingList AsShoppingList() 25 | { 26 | return new ShoppingList 27 | { 28 | Id = ShoppingListId, 29 | Title = Title 30 | }; 31 | } 32 | } 33 | 34 | public class ShoppingListsMap : ClassMap 35 | { 36 | public ShoppingListsMap() 37 | { 38 | Id(x => x.ShoppingListId) 39 | .GeneratedBy.GuidComb() 40 | .UnsavedValue(Guid.Empty); 41 | 42 | Map(x => x.UserId).Not.Nullable().Index("IDX_ShoppingLists_UserId").UniqueKey("UniqueTitle"); 43 | Map(x => x.Title).Not.Nullable().UniqueKey("UniqueTitle"); 44 | 45 | HasMany(x => x.Items) 46 | .KeyColumn("ShoppingListId") 47 | .Inverse() 48 | .Cascade.All(); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/DB/NLP/FormLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using KitchenPC.DB.Models; 4 | using KitchenPC.Ingredients; 5 | using KitchenPC.NLP; 6 | using NHibernate.Criterion; 7 | using NHibernate.Linq; 8 | 9 | namespace KitchenPC.DB 10 | { 11 | public class FormLoader : ISynonymLoader 12 | { 13 | readonly DatabaseAdapter adapter; 14 | 15 | public FormLoader(DatabaseAdapter adapter) 16 | { 17 | this.adapter = adapter; 18 | } 19 | 20 | public IEnumerable LoadSynonyms() 21 | { 22 | using (var session = adapter.GetStatelessSession()) 23 | { 24 | //Load synonyms 25 | var formSyn = session.Query() 26 | .OrderBy(p => p.Name) 27 | .Select(s => s.Name) 28 | .Distinct() 29 | .ToList(); 30 | 31 | return new List(formSyn.Select(s => new FormNode(s))); 32 | } 33 | } 34 | 35 | public Pairings LoadFormPairings() 36 | { 37 | using (var session = adapter.GetStatelessSession()) 38 | { 39 | var formSyn = session.QueryOver() 40 | .Fetch(prop => prop.Form).Eager() 41 | .List(); 42 | 43 | //Load all form pairings from db 44 | var pairings = new Pairings(); 45 | 46 | foreach (var syn in formSyn) 47 | { 48 | var name = syn.Name; 49 | var ing = syn.Ingredient.IngredientId; 50 | var form = syn.Form.IngredientFormId; 51 | var convType = syn.Form.UnitType; 52 | var displayName = syn.Form.FormDisplayName; 53 | var unitName = syn.Form.UnitName; 54 | int convMultiplier = syn.Form.ConvMultiplier; 55 | var formAmt = syn.Form.FormAmount; 56 | var formUnit = syn.Form.FormUnit; 57 | var amount = new Amount(formAmt, formUnit); 58 | 59 | pairings.Add( 60 | new NameIngredientPair(name, ing), 61 | new IngredientForm(form, ing, convType, displayName, unitName, convMultiplier, amount)); 62 | } 63 | 64 | return pairings; 65 | } 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/DB/NLP/IngredientGraphTransformer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using KitchenPC.Modeler; 4 | using NHibernate.Transform; 5 | 6 | namespace KitchenPC.DB 7 | { 8 | public class IngredientGraphTransformer : IResultTransformer 9 | { 10 | public static IngredientGraphTransformer Create() 11 | { 12 | return new IngredientGraphTransformer(); 13 | } 14 | 15 | IngredientGraphTransformer() 16 | { 17 | } 18 | 19 | public IList TransformList(IList collection) 20 | { 21 | return collection; 22 | } 23 | 24 | public object TransformTuple(object[] tuple, string[] aliases) 25 | { 26 | return IngredientBinding.Create 27 | ( 28 | (Guid) tuple[0], //R.IngredientId 29 | (Guid) tuple[1], //R.RecipeId 30 | (Single?) tuple[2], //R.Qty 31 | (Units) tuple[3], //R.Unit 32 | (UnitType) tuple[4], //I.ConversionType 33 | (int) tuple[5], //I.UnitWeight 34 | 35 | (Units) tuple[6], //F.UnitType 36 | (float) tuple[7], //F.FormAmount 37 | (Units) tuple[8] //F.FormUnit 38 | ); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DB/NLP/PrepLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using KitchenPC.DB.Models; 5 | using KitchenPC.NLP; 6 | 7 | namespace KitchenPC.DB 8 | { 9 | public class PrepLoader : ISynonymLoader 10 | { 11 | readonly DatabaseAdapter adapter; 12 | 13 | public PrepLoader(DatabaseAdapter adapter) 14 | { 15 | this.adapter = adapter; 16 | } 17 | 18 | public IEnumerable LoadSynonyms() 19 | { 20 | using (var session = adapter.GetStatelessSession()) 21 | { 22 | var forms = session.QueryOver().Select(p => p.Name).List(); 23 | var preps = session.QueryOver().Select(p => p.Name).List(); 24 | 25 | var ret = forms 26 | .Concat(preps) 27 | .Distinct() 28 | .Select(p => new PrepNode(p)) 29 | .ToList(); 30 | 31 | return ret; 32 | } 33 | } 34 | 35 | public Pairings LoadFormPairings() 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/DB/NLP/UnitLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using KitchenPC.DB.Models; 4 | using KitchenPC.Ingredients; 5 | using KitchenPC.NLP; 6 | using NHibernate.Criterion; 7 | using NHibernate.Linq; 8 | 9 | namespace KitchenPC.DB 10 | { 11 | public class UnitLoader : ISynonymLoader 12 | { 13 | readonly DatabaseAdapter adapter; 14 | 15 | public UnitLoader(DatabaseAdapter adapter) 16 | { 17 | this.adapter = adapter; 18 | } 19 | 20 | public IEnumerable LoadSynonyms() 21 | { 22 | using (var session = adapter.GetStatelessSession()) 23 | { 24 | //Load synonyms 25 | var unitSyn = session.Query() 26 | .OrderBy(p => p.Name) 27 | .Select(p => p.Name) 28 | .Distinct() 29 | .ToList(); 30 | 31 | return new List(unitSyn.Select(s => new CustomUnitNode(s))); 32 | } 33 | } 34 | 35 | public Pairings LoadFormPairings() 36 | { 37 | using (var session = adapter.GetStatelessSession()) 38 | { 39 | //Load all form pairings from db 40 | var unitSyn = session.QueryOver() 41 | .Fetch(prop => prop.Form).Eager() 42 | .List(); 43 | 44 | var pairings = new Pairings(); 45 | foreach (var syn in unitSyn) 46 | { 47 | pairings.Add(new NameIngredientPair( 48 | syn.Name.Trim(), 49 | syn.Ingredient.IngredientId), 50 | new IngredientForm( 51 | syn.Form.IngredientFormId, 52 | syn.Ingredient.IngredientId, 53 | syn.Form.UnitType, 54 | syn.Form.FormDisplayName, 55 | syn.Form.UnitName, 56 | syn.Form.ConvMultiplier, 57 | new Amount(syn.Form.FormAmount, syn.Form.FormUnit))); 58 | } 59 | 60 | return pairings; 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/DB/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("KitchenPC.DB")] 9 | [assembly: AssemblyDescription("KitchenPC Database Adapter")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("KitchenPC")] 12 | [assembly: AssemblyProduct("DB")] 13 | [assembly: AssemblyCopyright("Copyright © KitchenPC 2014")] 14 | [assembly: AssemblyTrademark("KitchenPC")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5050f0e8-e97f-40c7-807f-3a78de83298d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.9.0")] 36 | [assembly: AssemblyFileVersion("0.0.9.0")] 37 | -------------------------------------------------------------------------------- /src/DB/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/UnitTests/Mock/MockModelerDBLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Xml.Linq; 5 | using KitchenPC; 6 | using KitchenPC.Modeler; 7 | using KitchenPC.Recipes; 8 | 9 | namespace KPCServer.UnitTests 10 | { 11 | internal class MockModelerDBLoader : IModelerLoader 12 | { 13 | readonly RecipeBinding[] _dsRecipes; 14 | readonly IngredientBinding[] _dsIngredients; 15 | readonly RatingBinding[] _dsRatings; 16 | 17 | public MockModelerDBLoader(string filename) 18 | { 19 | var doc = XDocument.Load(filename); 20 | 21 | _dsRecipes = (from r in doc.Descendants("Recipe") 22 | select new RecipeBinding() 23 | { 24 | Id = new Guid(r.Attribute("Id").Value), 25 | Rating = Convert.ToByte(r.Attribute("Rating").Value), 26 | Tags = RecipeTags.Parse(r.Attribute("Tags").Value) 27 | }).ToArray(); 28 | 29 | _dsIngredients = (from u in doc.Descendants("Usage") 30 | select new IngredientBinding() 31 | { 32 | RecipeId = new Guid(u.Attribute("RecipeId").Value), 33 | IngredientId = new Guid(u.Attribute("IngredientId").Value), 34 | Qty = Convert.ToSingle(u.Attribute("Qty").Value), 35 | Unit = Unit.Parse(u.Attribute("Unit").Value) 36 | }).ToArray(); 37 | 38 | _dsRatings = (from r in doc.Descendants("Rating") 39 | select new RatingBinding() 40 | { 41 | UserId = new Guid(r.Attribute("UserId").Value), 42 | RecipeId = new Guid(r.Attribute("RecipeId").Value), 43 | Rating = Convert.ToByte(r.Attribute("Rating").Value) 44 | }).ToArray(); 45 | } 46 | 47 | public IEnumerable LoadRecipeGraph() 48 | { 49 | return _dsRecipes; 50 | } 51 | 52 | public IEnumerable LoadIngredientGraph() 53 | { 54 | return _dsIngredients; 55 | } 56 | 57 | public IEnumerable LoadRatingGraph() 58 | { 59 | return _dsRatings; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/UnitTests/Mock/Recipes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KitchenPC.Ingredients; 3 | using KitchenPC.Recipes; 4 | 5 | namespace KitchenPC.UnitTests.Mock 6 | { 7 | internal static class Recipes 8 | { 9 | public static Recipe MockRecipe(string title, string desc, RecipeTags tags = null) 10 | { 11 | var ret = new Recipe(Guid.NewGuid(), title, desc, null); 12 | 13 | ret.Method = "This is a mock recipe."; 14 | ret.OwnerAlias = "Fake Owner"; 15 | ret.OwnerId = Guid.NewGuid(); 16 | ret.Permalink = "http://www.kitchenpc.com/123"; 17 | ret.ServingSize = 5; 18 | ret.Tags = tags; 19 | 20 | return ret; 21 | } 22 | 23 | public static Recipe BEST_BROWNIES 24 | { 25 | get 26 | { 27 | var r = new Recipe(new Guid("b11a64a9-95b3-402f-8b82-312bad539d4e"), "Best Brownies", "from scratch!", ""); 28 | 29 | r.Tags = RecipeTag.NoMeat | RecipeTag.NoPork | RecipeTag.NoRedMeat | RecipeTag.Dessert; 30 | r.AvgRating = 5; 31 | r.CookTime = 40; 32 | r.PrepTime = 15; 33 | r.ServingSize = 24; 34 | r.AddIngredients(new IngredientUsage[] 35 | { 36 | new IngredientUsage(Ingredients.MARGARINE, Forms.MARGARINE_VOLUME, new Amount(1, Units.Cup), "in chunks"), 37 | new IngredientUsage(Ingredients.UNSWEETENED_BAKING_CHOCOLATE_SQUARES, Forms.UNSWEETENED_BAKING_CHOCOLATE_SQUARES_WEIGHT, new Amount(1, Units.Ounce), ""), 38 | new IngredientUsage(Ingredients.GRANULATED_SUGAR, Forms.GRANULATED_SUGAR_VOLUME, new Amount(2.66667f, Units.Cup), ""), 39 | new IngredientUsage(Ingredients.EGGS, Forms.EGGS_UNIT, new Amount(4, Units.Unit), "large"), 40 | new IngredientUsage(Ingredients.VANILLA_EXTRACT, Forms.VANILLA_EXTRACT_VOLUME, new Amount(2, Units.Teaspoon), ""), 41 | new IngredientUsage(Ingredients.ALL_PURPOSE_FLOUR, Forms.ALL_PURPOSE_FLOUR_SIFTED, new Amount(1, Units.Cup), "") 42 | }); 43 | 44 | return r; 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("KitchenPC")] 9 | [assembly: AssemblyDescription("KitchenPC Unit Tests")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("KitchenPC")] 12 | [assembly: AssemblyProduct("UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © KitchenPC 2014")] 14 | [assembly: AssemblyTrademark("KitchenPC")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9f663b61-439d-4171-b953-c69d42ff2893")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.9.0")] 36 | [assembly: AssemblyFileVersion("0.0.9.0")] 37 | -------------------------------------------------------------------------------- /src/UnitTests/TestFormLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using KitchenPC.Ingredients; 3 | using KitchenPC.NLP; 4 | 5 | namespace KitchenPC.UnitTests 6 | { 7 | internal class TestFormLoader : ISynonymLoader 8 | { 9 | public IEnumerable LoadSynonyms() 10 | { 11 | FormNode[] nodes = 12 | { 13 | new FormNode("melted"), 14 | new FormNode("shredded"), 15 | new FormNode("diced") 16 | }; 17 | 18 | return nodes; 19 | } 20 | 21 | public Pairings LoadFormPairings() 22 | { 23 | //TODO: This will come from a database of pairs that maps every possible unit to a default form of an ingredient 24 | var pairings = new Pairings(); 25 | pairings.Add(new NameIngredientPair("melted", TestIngredientLoader.ING_CHEESE), new IngredientForm(TestIngredientLoader.FORM_CHEESE_MELTED, TestIngredientLoader.ING_CHEESE, Units.Cup, "melted", "", 0, null)); 26 | pairings.Add(new NameIngredientPair("shredded", TestIngredientLoader.ING_CHEESE), new IngredientForm(TestIngredientLoader.FORM_CHEESE_SHREDDED, TestIngredientLoader.ING_CHEESE, Units.Cup, "shredded", "", 0, null)); 27 | pairings.Add(new NameIngredientPair("diced", TestIngredientLoader.ING_CHEESE), new IngredientForm(TestIngredientLoader.FORM_CHEESE_DICED, TestIngredientLoader.ING_CHEESE, Units.Cup, "diced", "", 0, null)); 28 | 29 | return pairings; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/UnitTests/TestPrepLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using KitchenPC.NLP; 4 | 5 | namespace KitchenPC.UnitTests 6 | { 7 | internal class TestPrepLoader : ISynonymLoader 8 | { 9 | public Pairings LoadFormPairings() 10 | { 11 | throw new NotImplementedException(); 12 | } 13 | 14 | public IEnumerable LoadSynonyms() 15 | { 16 | return new PrepNode[] 17 | { 18 | "sliced", "shredded", "crumbled", "diced", "chopped" //Test prep nodes (approved prep notes for any ingredient) 19 | }; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/UnitTests/TestUnitLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using KitchenPC.Ingredients; 3 | using KitchenPC.NLP; 4 | 5 | namespace KitchenPC.UnitTests 6 | { 7 | internal class TestUnitLoader : ISynonymLoader 8 | { 9 | public IEnumerable LoadSynonyms() 10 | { 11 | //Add some test unit types, this will eventually come from database 12 | UnitNode[] units = 13 | { 14 | new CustomUnitNode("head"), new CustomUnitNode("heads") 15 | }; 16 | 17 | return units; 18 | } 19 | 20 | public Pairings LoadFormPairings() 21 | { 22 | //TODO: This will come from a database of pairs that maps every possible unit to a default form of an ingredient 23 | var pairings = new Pairings(); 24 | var pair = new NameIngredientPair("head", TestIngredientLoader.ING_LETTUCE); 25 | var form = new IngredientForm(TestIngredientLoader.FORM_LETTUCE_HEAD, TestIngredientLoader.ING_LETTUCE, Units.Unit, null, "head/heads", 0, null); 26 | pairings.Add(pair, form); 27 | 28 | return pairings; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/UnitTests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | . 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/packages/FluentNHibernate.2.0.3.0/FluentNHibernate.2.0.3.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/FluentNHibernate.2.0.3.0/FluentNHibernate.2.0.3.0.nupkg -------------------------------------------------------------------------------- /src/packages/FluentNHibernate.2.0.3.0/FluentNHibernate.2.0.3.0.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FluentNHibernate 5 | 2.0.3.0 6 | FluentNHibernate 7 | James Gregory and contributors 8 | James Gregory and contributors 9 | http://github.com/jagregory/fluent-nhibernate/raw/master/LICENSE.txt 10 | http://fluentnhibernate.org/ 11 | false 12 | Fluent, XML-less, compile safe, automated, convention-based mappings for NHibernate. 13 | en-US 14 | orm dal nhibernate conventions 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/packages/FluentNHibernate.2.0.3.0/lib/net40/FluentNHibernate.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/FluentNHibernate.2.0.3.0/lib/net40/FluentNHibernate.dll -------------------------------------------------------------------------------- /src/packages/FluentNHibernate.2.0.3.0/lib/net40/FluentNHibernate.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/FluentNHibernate.2.0.3.0/lib/net40/FluentNHibernate.pdb -------------------------------------------------------------------------------- /src/packages/Iesi.Collections.4.0.1.4000/Iesi.Collections.4.0.1.4000.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Iesi.Collections.4.0.1.4000/Iesi.Collections.4.0.1.4000.nupkg -------------------------------------------------------------------------------- /src/packages/Iesi.Collections.4.0.1.4000/Iesi.Collections.4.0.1.4000.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Iesi.Collections 5 | 4.0.1.4000 6 | Aidant Systems, Jason Smith, NHibernate community 7 | Aidant Systems, Jason Smith, NHibernate community 8 | https://github.com/nhibernate/iesi.collections 9 | false 10 | The System.Collections namespace in the .NET Framework provides a number of collection types that are extremely useful for manipulating data in memory. However, some specialized implementations of ISet are not available. Iesi.Collections 4.0 for .Net 4.0 contains the LinkedHashSet (preserves insertion order), the ReadOnlySet and the SynchronizedSet. The latter two wrap an actual set. 11 | Additional implementations of System.Collections.Generic.ISet<T>. 12 | en-US 13 | Collections 14 | 15 | -------------------------------------------------------------------------------- /src/packages/Iesi.Collections.4.0.1.4000/lib/net40/Iesi.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Iesi.Collections.4.0.1.4000/lib/net40/Iesi.Collections.dll -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/FireBird.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 17 | 18 | 19 | NHibernate.Driver.FirebirdClientDriver 20 | 21 | Server=localhost; 22 | Database=C:\nhibernate.fdb; 23 | User=SYSDBA;Password=masterkey 24 | 25 | false 26 | NHibernate.Dialect.FirebirdDialect 27 | 60 28 | true 1, false 0, yes 1, no 0 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/MSSQL.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | NHibernate.Driver.SqlClientDriver 11 | 12 | Server=(local);initial catalog=nhibernate;Integrated Security=SSPI 13 | 14 | NHibernate.Dialect.MsSql2008Dialect 15 | 16 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/MySql.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | NHibernate.Driver.MySqlDataDriver 11 | 12 | Database=test;Data Source=someip;User Id=blah;Password=blah 13 | 14 | NHibernate.Dialect.MySQLDialect 15 | 16 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/Oracle.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | NHibernate.Driver.OracleClientDriver 11 | 12 | User ID=nhibernate;Password=nhibernate;Data Source=localhost 13 | 14 | false 15 | NHibernate.Dialect.OracleDialect 16 | true 1, false 0, yes 'Y', no 'N' 17 | 18 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/PostgreSQL.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | NHibernate.Driver.NpgsqlDriver 10 | 11 | Server=localhost;Database=nhibernate;User ID=nhibernate;Password=nhibernate; 12 | 13 | NHibernate.Dialect.PostgreSQL82Dialect 14 | 15 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/SQLite.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | NHibernate.Driver.SQLite20Driver 10 | 11 | Data Source=nhibernate.db 12 | 13 | NHibernate.Dialect.SQLiteDialect 14 | 15 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/SybaseASE.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | NHibernate.Driver.SybaseAseClientDriver 10 | 11 | Data Source=10.0.0.1;Port=5000;Database=nhibernate;User ID=nhibernate;Password=password 12 | 13 | NHibernate.Dialect.SybaseASE15Dialect 14 | true=1;false=0 15 | 16 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/ConfigurationTemplates/SybaseSQLAnywhere.cfg.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | NHibernate.Driver.SybaseSQLAnywhereDriver 10 | 11 | UID=DBA;PWD=sql;Server=localhost;DBN=nhibernate;DBF=c:\nhibernate.db;ASTOP=No 12 | 13 | NHibernate.Dialect.SybaseSQLAnywhere12Dialect 14 | true=1;false=0 15 | 16 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/NHibernate.4.0.4.4000.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NHibernate.4.0.4.4000/NHibernate.4.0.4.4000.nupkg -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/NHibernate.4.0.4.4000.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NHibernate 5 | 4.0.4.4000 6 | NHibernate community, Hibernate community 7 | NHibernate community, Hibernate community 8 | https://raw.github.com/nhibernate/nhibernate-core/master/lgpl.txt 9 | http://nhibernate.info 10 | https://raw.github.com/nhibernate/nhibernate-core/master/logo/NHibernate-NuGet.png 11 | false 12 | NHibernate is a mature, open source object-relational mapper for the .NET framework. It is actively developed, fully featured and used in thousands of successful projects. 13 | NHibernate is a mature, open source object-relational mapper for the .NET framework. It is actively developed, fully featured and used in thousands of successful projects. 14 | en-US 15 | ORM DataBase DAL ObjectRelationalMapping 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/NHibernate.releasenotes.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NHibernate.4.0.4.4000/NHibernate.releasenotes.txt -------------------------------------------------------------------------------- /src/packages/NHibernate.4.0.4.4000/lib/net40/NHibernate.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NHibernate.4.0.4.4000/lib/net40/NHibernate.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Charlie Poole 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/NOTICES.txt: -------------------------------------------------------------------------------- 1 | NUnit 3.0 is based on earlier versions of NUnit, with Portions 2 | 3 | Copyright (c) 2002-2014 Charlie Poole or 4 | Copyright (c) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or 5 | Copyright (c) 2000-2002 Philip A. Craig 6 | -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/NUnit.3.4.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/NUnit.3.4.1.nupkg -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/NUnit.3.4.1.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NUnit 5 | 3.4.1 6 | NUnit 7 | Charlie Poole 8 | Charlie Poole 9 | http://nunit.org/nuget/nunit3-license.txt 10 | http://nunit.org/ 11 | http://nunit.org/nuget/nunitv3_32x32.png 12 | false 13 | NUnit features a fluent assert syntax, parameterized, generic and theory tests and is user-extensible. 14 | 15 | This package includes the NUnit 3.0 framework assembly, which is referenced by your tests. You will need to install version 3.0 of the nunit3-console program or a third-party runner that supports NUnit 3.0 in order to execute tests. Runners intended for use with NUnit 2.x will not run 3.0 tests correctly. 16 | 17 | Supported platforms: 18 | - .NET 2.0+ 19 | - .NET Core (Universal Windows Apps 10+, DNX Core 5+) 20 | - Windows 8 21 | - Windows Phone 8 (Silverlight) 22 | - Universal (Windows Phone 8.1+, Windows 8.1+) 23 | - Xamarin (MonoTouch, MonoAndroid, Xamarin iOS Universal) 24 | - Portable Libraries (supporting Profile259) 25 | NUnit is a unit-testing framework for all .Net languages with a strong TDD focus. 26 | This package includes the NUnit 3.0 framework assembly, which is referenced by your tests. You will need to install version 3.0 of the nunit3-console program or a third-party runner that supports NUnit 3.0 in order to execute tests. Runners intended for use with NUnit 2.x will not run 3.0 tests correctly. 27 | Copyright (c) 2016 Charlie Poole 28 | en-US 29 | nunit test testing tdd framework fluent assert theory plugin addin 30 | 31 | -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/dotnet/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/dotnet/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/net20/NUnit.System.Linq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/net20/NUnit.System.Linq.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/net20/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/net20/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/net35/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/net35/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/net40/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/net40/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/net45/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/net45/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/NUnit.3.4.1/lib/portable-net45+win8+wp8+wpa81+Xamarin.Mac+MonoAndroid10+MonoTouch10+Xamarin.iOS10/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/NUnit.3.4.1/lib/portable-net45+win8+wp8+wpa81+Xamarin.Mac+MonoAndroid10+MonoTouch10+Xamarin.iOS10/nunit.framework.dll -------------------------------------------------------------------------------- /src/packages/Npgsql.3.1.7/Npgsql.3.1.7.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Npgsql.3.1.7/Npgsql.3.1.7.nupkg -------------------------------------------------------------------------------- /src/packages/Npgsql.3.1.7/Npgsql.3.1.7.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Npgsql 5 | 3.1.7 6 | Npgsql 7 | Npgsql 8 | https://raw.githubusercontent.com/npgsql/npgsql/develop/LICENSE.txt 9 | http://www.npgsql.org/img/postgresql.gif 10 | false 11 | Npgsql 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/packages/Npgsql.3.1.7/lib/net45/Npgsql.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Npgsql.3.1.7/lib/net45/Npgsql.dll -------------------------------------------------------------------------------- /src/packages/Npgsql.3.1.7/lib/net451/Npgsql.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Npgsql.3.1.7/lib/net451/Npgsql.dll -------------------------------------------------------------------------------- /src/packages/Npgsql.3.1.7/lib/netstandard1.3/Npgsql.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/Npgsql.3.1.7/lib/netstandard1.3/Npgsql.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net10-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net10-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net11-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net11-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net20-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net20-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net35-client/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net35-client/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net35-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net35-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net40-client/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net40-client/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net40-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net40-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/lib/net45-full/log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/lib/net45-full/log4net.dll -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/log4net.2.0.5.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KitchenPC/core/34e0729f4aa947ed66d3ebb7d43d078acb3fe352/src/packages/log4net.2.0.5/log4net.2.0.5.nupkg -------------------------------------------------------------------------------- /src/packages/log4net.2.0.5/log4net.2.0.5.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | log4net 5 | 2.0.5 6 | log4net [1.2.15] 7 | Apache Software Foundation 8 | Apache Software Foundation 9 | http://logging.apache.org/log4net/license.html 10 | http://logging.apache.org/log4net/ 11 | false 12 | log4net is a tool to help the programmer output log statements to a variety of output targets. In case of problems with an application, it is helpful to enable logging so that the problem can be located. With log4net it is possible to enable logging at runtime without modifying the application binary. The log4net package is designed so that log statements can remain in shipped code without incurring a high performance cost. It follows that the speed of logging (or rather not logging) is crucial. 13 | 14 | At the same time, log output can be so voluminous that it quickly becomes overwhelming. One of the distinctive features of log4net is the notion of hierarchical loggers. Using these loggers it is possible to selectively control which log statements are output at arbitrary granularity. 15 | 16 | log4net is designed with two distinct goals in mind: speed and flexibility 17 | The Apache log4net library is a tool to help the programmer output log statements to a variety of output targets. 18 | logging log tracing logfiles 19 | 20 | -------------------------------------------------------------------------------- /src/packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------