private ProducerFrameworkRecipe ReadRecipe(IDictionary <string, object> raw)
 {
     try
     {
         ProducerFrameworkRecipe recipe = new ProducerFrameworkRecipe();
         recipe.InputId           = raw["InputKey"] as int?;
         recipe.MachineId         = (int)raw["MachineID"];
         recipe.Ingredients       = ((List <Dictionary <string, object> >)raw["Ingredients"]).Select(this.ReadIngredient).ToArray();
         recipe.ExceptIngredients = ((List <Dictionary <string, object> >)raw["ExceptIngredients"]).Select(this.ReadIngredient).Select(p => p.InputId).ToArray();
         recipe.OutputId          = (int)raw["Output"];
         recipe.MinOutput         = (int)raw["MinOutput"];
         recipe.MaxOutput         = (int)raw["MaxOutput"];
         recipe.PreserveType      = (SObject.PreserveType?)raw["PreserveType"];
         recipe.OutputChance      = (double)raw["OutputChance"];
         return(recipe);
     }
     catch (Exception ex)
     {
         if (!this.LoggedInvalidRecipeError)
         {
             this.LoggedInvalidRecipeError = true;
             this.Monitor.Log("Failed to load some recipes from Producer Framework Mod. Some custom machines may not appear in lookups.", LogLevel.Warn);
             this.Monitor.Log(ex.ToString());
         }
         return(null);
     }
 }
        /*********
        ** Private methods
        *********/
        /// <summary>Read the metadata for a recipe provided by <see cref="GetRecipes()"/> or <see cref="GetRecipes(SObject)"/>.</summary>
        /// <param name="raw">The raw recipe data.</param>
        private ProducerFrameworkRecipe ReadRecipe(IDictionary <string, object> raw)
        {
            ProducerFrameworkRecipe recipe = new ProducerFrameworkRecipe();

            recipe.InputId           = raw["InputKey"] as int?;
            recipe.MachineId         = (int)raw["MachineID"];
            recipe.Ingredients       = ((List <Dictionary <string, object> >)raw["Ingredients"]).ToDictionary(p => (int)p["ID"], p => (int)p["Count"]);
            recipe.ExceptIngredients = ((List <Dictionary <string, object> >)raw["ExceptIngredients"]).Select(p => (int)p["ID"]).ToArray();
            recipe.OutputId          = (int)raw["Output"];
            recipe.MinOutput         = (int)raw["MinOutput"];
            recipe.MaxOutput         = (int)raw["MaxOutput"];
            recipe.PreserveType      = (SObject.PreserveType?)raw["PreserveType"];
            recipe.OutputChance      = (double)raw["OutputChance"];
            return(recipe);
        }