mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Formatted includes/data_generation
This commit is contained in:
@@ -14,28 +14,28 @@
|
|||||||
* @brief Interface for data generator implementations.
|
* @brief Interface for data generator implementations.
|
||||||
*/
|
*/
|
||||||
class DataGenerator {
|
class DataGenerator {
|
||||||
public:
|
public:
|
||||||
virtual ~DataGenerator() = default;
|
virtual ~DataGenerator() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates brewery data for a location.
|
* @brief Generates brewery data for a location.
|
||||||
*
|
*
|
||||||
* @param city Enriched city the brewery is associated with.
|
* @param city Enriched city the brewery is associated with.
|
||||||
* @return Brewery generation result.
|
* @return Brewery generation result.
|
||||||
*/
|
*/
|
||||||
virtual BreweryResult GenerateBrewery(const EnrichedCity& city) = 0;
|
virtual BreweryResult GenerateBrewery(const EnrichedCity& city) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates a user profile grounded in a sampled name and persona.
|
* @brief Generates a user profile grounded in a sampled name and persona.
|
||||||
*
|
*
|
||||||
* @param city Enriched city the user is associated with.
|
* @param city Enriched city the user is associated with.
|
||||||
* @param persona Persona archetype grounding the generated bio.
|
* @param persona Persona archetype grounding the generated bio.
|
||||||
* @param name Sampled first/last name (and gender)
|
* @param name Sampled first/last name (and gender)
|
||||||
* @return User generation result.
|
* @return User generation result.
|
||||||
*/
|
*/
|
||||||
virtual UserResult GenerateUser(const EnrichedCity& city,
|
virtual UserResult GenerateUser(const EnrichedCity& city,
|
||||||
const UserPersona& persona,
|
const UserPersona& persona,
|
||||||
const Name& name) = 0;
|
const Name& name) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_DATA_GENERATOR_H_
|
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_DATA_GENERATOR_H_
|
||||||
|
|||||||
@@ -26,110 +26,112 @@ struct llama_context;
|
|||||||
* @brief Data generator implementation backed by llama.cpp.
|
* @brief Data generator implementation backed by llama.cpp.
|
||||||
*/
|
*/
|
||||||
class LlamaGenerator final : public DataGenerator {
|
class LlamaGenerator final : public DataGenerator {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Constructs a generator using parsed application options and loads
|
* @brief Constructs a generator using parsed application options and loads
|
||||||
* the configured model immediately.
|
* the configured model immediately.
|
||||||
*
|
*
|
||||||
* @param options Parsed application options.
|
* @param options Parsed application options.
|
||||||
* @param model_path Filesystem path to GGUF model assets.
|
* @param model_path Filesystem path to GGUF model assets.
|
||||||
* @param prompt_formatter Formatter that produces model-specific prompts.
|
* @param prompt_formatter Formatter that produces model-specific prompts.
|
||||||
* @param prompt_directory Directory service for loading named prompt files.
|
* @param prompt_directory Directory service for loading named prompt files.
|
||||||
*/
|
*/
|
||||||
LlamaGenerator(const ApplicationOptions& options,
|
LlamaGenerator(const ApplicationOptions& options,
|
||||||
const std::string& model_path, std::shared_ptr<ILogger> logger,
|
const std::string& model_path,
|
||||||
std::unique_ptr<IPromptFormatter> prompt_formatter,
|
std::shared_ptr<ILogger> logger,
|
||||||
std::unique_ptr<IPromptDirectory> prompt_directory);
|
std::unique_ptr<IPromptFormatter> prompt_formatter,
|
||||||
|
std::unique_ptr<IPromptDirectory> prompt_directory);
|
||||||
|
|
||||||
~LlamaGenerator() override;
|
~LlamaGenerator() override;
|
||||||
|
|
||||||
LlamaGenerator(const LlamaGenerator&) = delete;
|
LlamaGenerator(const LlamaGenerator&) = delete;
|
||||||
LlamaGenerator& operator=(const LlamaGenerator&) = delete;
|
LlamaGenerator& operator=(const LlamaGenerator&) = delete;
|
||||||
LlamaGenerator(LlamaGenerator&&) = delete;
|
LlamaGenerator(LlamaGenerator&&) = delete;
|
||||||
LlamaGenerator& operator=(LlamaGenerator&&) = delete;
|
LlamaGenerator& operator=(LlamaGenerator&&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates brewery data for a specific location.
|
* @brief Generates brewery data for a specific location.
|
||||||
*
|
*
|
||||||
* @param location City object.
|
* @param location City object.
|
||||||
* @param region_context Additional regional context.
|
* @param region_context Additional regional context.
|
||||||
* @return Generated brewery result.
|
* @return Generated brewery result.
|
||||||
*/
|
*/
|
||||||
BreweryResult GenerateBrewery(const EnrichedCity&) override;
|
BreweryResult GenerateBrewery(const EnrichedCity&) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generates a user profile grounded in a sampled name and persona.
|
* @brief Generates a user profile grounded in a sampled name and persona.
|
||||||
*
|
*
|
||||||
* @param city Enriched city the user is associated with.
|
* @param city Enriched city the user is associated with.
|
||||||
* @param persona Persona archetype grounding the generated bio.
|
* @param persona Persona archetype grounding the generated bio.
|
||||||
* @param name Sampled first/last name -- not LLM-invented.
|
* @param name Sampled first/last name -- not LLM-invented.
|
||||||
* @return Generated user profile.
|
* @return Generated user profile.
|
||||||
*/
|
*/
|
||||||
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
||||||
const Name& name) override;
|
const Name& name) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int32_t kDefaultMaxTokens = 10000;
|
static constexpr int32_t kDefaultMaxTokens = 10000;
|
||||||
static constexpr float kDefaultSamplingTopP = 0.95F;
|
static constexpr float kDefaultSamplingTopP = 0.95F;
|
||||||
static constexpr uint32_t kDefaultSamplingTopK = 64;
|
static constexpr uint32_t kDefaultSamplingTopK = 64;
|
||||||
static constexpr uint32_t kDefaultContextSize = 8192;
|
static constexpr uint32_t kDefaultContextSize = 8192;
|
||||||
|
|
||||||
struct ModelDeleter {
|
struct ModelDeleter {
|
||||||
void operator()(llama_model* model) const noexcept;
|
void operator()(llama_model* model) const noexcept;
|
||||||
};
|
};
|
||||||
struct ContextDeleter {
|
struct ContextDeleter {
|
||||||
void operator()(llama_context* context) const noexcept;
|
void operator()(llama_context* context) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ModelHandle = std::unique_ptr<llama_model, ModelDeleter>;
|
using ModelHandle = std::unique_ptr<llama_model, ModelDeleter>;
|
||||||
using ContextHandle = std::unique_ptr<llama_context, ContextDeleter>;
|
using ContextHandle = std::unique_ptr<llama_context, ContextDeleter>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loads model and prepares inference context.
|
* @brief Loads model and prepares inference context.
|
||||||
*
|
*
|
||||||
* @param model_path Filesystem path to GGUF model.
|
* @param model_path Filesystem path to GGUF model.
|
||||||
*/
|
*/
|
||||||
void Load(const std::string& model_path);
|
void Load(const std::string& model_path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Infers text from separate system and user prompts.
|
* @brief Infers text from separate system and user prompts.
|
||||||
*
|
*
|
||||||
* This helps chat-capable models preserve system-role behavior instead of
|
* This helps chat-capable models preserve system-role behavior instead of
|
||||||
* concatenating system text into user input.
|
* concatenating system text into user input.
|
||||||
*
|
*
|
||||||
* @param system_prompt System role prompt.
|
* @param system_prompt System role prompt.
|
||||||
* @param prompt User prompt.
|
* @param prompt User prompt.
|
||||||
* @param max_tokens Maximum tokens to generate.
|
* @param max_tokens Maximum tokens to generate.
|
||||||
* @param grammar Optional GBNF grammar constraining generated output.
|
* @param grammar Optional GBNF grammar constraining generated output.
|
||||||
* @return Generated text.
|
* @return Generated text.
|
||||||
*/
|
*/
|
||||||
std::string Infer(const std::string& system_prompt, const std::string& prompt,
|
std::string Infer(const std::string& system_prompt,
|
||||||
int max_tokens = kDefaultMaxTokens,
|
const std::string& prompt,
|
||||||
std::string_view grammar = {});
|
int max_tokens = kDefaultMaxTokens,
|
||||||
|
std::string_view grammar = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Runs inference on an already-formatted prompt.
|
* @brief Runs inference on an already-formatted prompt.
|
||||||
*
|
*
|
||||||
* @param formatted_prompt Prompt preformatted for model chat template.
|
* @param formatted_prompt Prompt preformatted for model chat template.
|
||||||
* @param max_tokens Maximum tokens to generate.
|
* @param max_tokens Maximum tokens to generate.
|
||||||
* @param grammar Optional GBNF grammar constraining generated output.
|
* @param grammar Optional GBNF grammar constraining generated output.
|
||||||
* @return Generated text.
|
* @return Generated text.
|
||||||
*/
|
*/
|
||||||
std::string InferFormatted(const std::string& formatted_prompt,
|
std::string InferFormatted(const std::string& formatted_prompt,
|
||||||
int max_tokens = kDefaultMaxTokens,
|
int max_tokens = kDefaultMaxTokens,
|
||||||
std::string_view grammar = {});
|
std::string_view grammar = {});
|
||||||
|
|
||||||
ModelHandle model_;
|
ModelHandle model_;
|
||||||
ContextHandle context_;
|
ContextHandle context_;
|
||||||
float sampling_temperature_ = 1.0F;
|
float sampling_temperature_ = 1.0F;
|
||||||
float sampling_top_p_ = kDefaultSamplingTopP;
|
float sampling_top_p_ = kDefaultSamplingTopP;
|
||||||
uint32_t sampling_top_k_ = kDefaultSamplingTopK;
|
uint32_t sampling_top_k_ = kDefaultSamplingTopK;
|
||||||
std::mt19937 rng_;
|
std::mt19937 rng_;
|
||||||
uint32_t n_ctx_ = kDefaultContextSize;
|
uint32_t n_ctx_ = kDefaultContextSize;
|
||||||
int n_gpu_layers_ = 0;
|
int n_gpu_layers_ = 0;
|
||||||
std::shared_ptr<ILogger> logger_;
|
std::shared_ptr<ILogger> logger_;
|
||||||
std::unique_ptr<IPromptFormatter> prompt_formatter_;
|
std::unique_ptr<IPromptFormatter> prompt_formatter_;
|
||||||
std::unique_ptr<IPromptDirectory> prompt_directory_;
|
std::unique_ptr<IPromptDirectory> prompt_directory_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_H_
|
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_LLAMA_GENERATOR_H_
|
||||||
|
|||||||
@@ -16,128 +16,129 @@
|
|||||||
* @brief Mock generator used for deterministic, model-free outputs.
|
* @brief Mock generator used for deterministic, model-free outputs.
|
||||||
*/
|
*/
|
||||||
class MockGenerator final : public DataGenerator {
|
class MockGenerator final : public DataGenerator {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Generates deterministic brewery data for a location.
|
* @brief Generates deterministic brewery data for a location.
|
||||||
*
|
*
|
||||||
* @param enriched_city
|
* @param enriched_city
|
||||||
* @return Generated brewery result.
|
* @return Generated brewery result.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
BreweryResult GenerateBrewery(const EnrichedCity& enriched_city) override;
|
BreweryResult GenerateBrewery(const EnrichedCity& enriched_city) override;
|
||||||
/**
|
/**
|
||||||
* @brief Generates deterministic user data grounded in a sampled name and
|
* @brief Generates deterministic user data grounded in a sampled name and
|
||||||
* persona.
|
* persona.
|
||||||
|
|
||||||
* @return Generated user result.
|
* @return Generated user result.
|
||||||
*/
|
*/
|
||||||
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
UserResult GenerateUser(const EnrichedCity& city, const UserPersona& persona,
|
||||||
const Name& name) override;
|
const Name& name) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Combines two strings into a stable hash value.
|
* @brief Combines two strings into a stable hash value.
|
||||||
*
|
*
|
||||||
* @param location City and country names.
|
* @param location City and country names.
|
||||||
* @return Deterministic hash value.
|
* @return Deterministic hash value.
|
||||||
*/
|
*/
|
||||||
static size_t DeterministicHash(const City& location);
|
static size_t DeterministicHash(const City& location);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Combines city, persona, and name into a stable hash value.
|
* @brief Combines city, persona, and name into a stable hash value.
|
||||||
*
|
*
|
||||||
* @param location City and country names.
|
* @param location City and country names.
|
||||||
* @param persona Persona archetype.
|
* @param persona Persona archetype.
|
||||||
* @param name Sampled first/last name.
|
* @param name Sampled first/last name.
|
||||||
* @return Deterministic hash value.
|
* @return Deterministic hash value.
|
||||||
*/
|
*/
|
||||||
static size_t DeterministicHash(const City& location,
|
static size_t DeterministicHash(const City& location,
|
||||||
const UserPersona& persona, const Name& name);
|
const UserPersona& persona,
|
||||||
|
const Name& name);
|
||||||
|
|
||||||
// Hash stride constants for deterministic distribution across fixed-size
|
// Hash stride constants for deterministic distribution across fixed-size
|
||||||
// arrays. These coprime strides spread hash values uniformly without
|
// arrays. These coprime strides spread hash values uniformly without
|
||||||
// clustering, ensuring diverse output across different hash inputs.
|
// clustering, ensuring diverse output across different hash inputs.
|
||||||
static constexpr size_t kNounHashStride = 7;
|
static constexpr size_t kNounHashStride = 7;
|
||||||
static constexpr size_t kDescriptionHashStride = 13;
|
static constexpr size_t kDescriptionHashStride = 13;
|
||||||
static constexpr size_t kBioHashStride = 11;
|
static constexpr size_t kBioHashStride = 11;
|
||||||
static constexpr size_t kActivityWeightHashStride = 17;
|
static constexpr size_t kActivityWeightHashStride = 17;
|
||||||
static constexpr size_t kActivityWeightHashRange = 1000;
|
static constexpr size_t kActivityWeightHashRange = 1000;
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 18> kBreweryAdjectives = {
|
static constexpr std::array<std::string_view, 18> kBreweryAdjectives = {
|
||||||
"Craft", "Heritage", "Local", "Artisan", "Pioneer", "Golden",
|
"Craft", "Heritage", "Local", "Artisan", "Pioneer", "Golden",
|
||||||
"Modern", "Classic", "Summit", "Northern", "Riverstone", "Barrel",
|
"Modern", "Classic", "Summit", "Northern", "Riverstone", "Barrel",
|
||||||
"Hinterland", "Harbor", "Wild", "Granite", "Copper", "Maple"};
|
"Hinterland", "Harbor", "Wild", "Granite", "Copper", "Maple"};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 18> kBreweryNouns = {
|
static constexpr std::array<std::string_view, 18> kBreweryNouns = {
|
||||||
"Brewing Co.", "Brewery", "Bier Haus", "Taproom", "Works",
|
"Brewing Co.", "Brewery", "Bier Haus", "Taproom", "Works",
|
||||||
"House", "Fermentery", "Ale Co.", "Cellars", "Collective",
|
"House", "Fermentery", "Ale Co.", "Cellars", "Collective",
|
||||||
"Project", "Foundry", "Malthouse", "Public House", "Co-op",
|
"Project", "Foundry", "Malthouse", "Public House", "Co-op",
|
||||||
"Lab", "Beer Hall", "Guild"};
|
"Lab", "Beer Hall", "Guild"};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 18> kBreweryDescriptions = {
|
static constexpr std::array<std::string_view, 18> kBreweryDescriptions = {
|
||||||
"Handcrafted pale ales and seasonal IPAs with local ingredients.",
|
"Handcrafted pale ales and seasonal IPAs with local ingredients.",
|
||||||
"Traditional lagers and experimental sours in small batches.",
|
"Traditional lagers and experimental sours in small batches.",
|
||||||
"Award-winning stouts and wildly hoppy blonde ales.",
|
"Award-winning stouts and wildly hoppy blonde ales.",
|
||||||
"Craft brewery specializing in Belgian-style triples and dark "
|
"Craft brewery specializing in Belgian-style triples and dark "
|
||||||
"porters.",
|
"porters.",
|
||||||
"Modern brewery blending tradition with bold experimental flavors.",
|
"Modern brewery blending tradition with bold experimental flavors.",
|
||||||
"Neighborhood-focused taproom pouring crisp pilsners and citrusy "
|
"Neighborhood-focused taproom pouring crisp pilsners and citrusy "
|
||||||
"pale "
|
"pale "
|
||||||
"ales.",
|
"ales.",
|
||||||
"Small-batch brewery known for barrel-aged releases and smoky "
|
"Small-batch brewery known for barrel-aged releases and smoky "
|
||||||
"lagers.",
|
"lagers.",
|
||||||
"Independent brewhouse pairing farmhouse ales with rotating food "
|
"Independent brewhouse pairing farmhouse ales with rotating food "
|
||||||
"pop-ups.",
|
"pop-ups.",
|
||||||
"Community brewpub making balanced bitters, saisons, and hazy IPAs.",
|
"Community brewpub making balanced bitters, saisons, and hazy IPAs.",
|
||||||
"Experimental nanobrewery exploring local yeast and regional "
|
"Experimental nanobrewery exploring local yeast and regional "
|
||||||
"grains.",
|
"grains.",
|
||||||
"Family-run brewery producing smooth amber ales and robust porters.",
|
"Family-run brewery producing smooth amber ales and robust porters.",
|
||||||
"Urban brewery crafting clean lagers and bright, fruit-forward "
|
"Urban brewery crafting clean lagers and bright, fruit-forward "
|
||||||
"sours.",
|
"sours.",
|
||||||
"Riverfront brewhouse featuring oak-matured ales and seasonal "
|
"Riverfront brewhouse featuring oak-matured ales and seasonal "
|
||||||
"blends.",
|
"blends.",
|
||||||
"Modern taproom focused on sessionable lagers and classic pub "
|
"Modern taproom focused on sessionable lagers and classic pub "
|
||||||
"styles.",
|
"styles.",
|
||||||
"Brewery rooted in tradition with a lineup of malty reds and crisp "
|
"Brewery rooted in tradition with a lineup of malty reds and crisp "
|
||||||
"lagers.",
|
"lagers.",
|
||||||
"Creative brewery offering rotating collaborations and limited "
|
"Creative brewery offering rotating collaborations and limited "
|
||||||
"draft-only "
|
"draft-only "
|
||||||
"pours.",
|
"pours.",
|
||||||
"Locally inspired brewery serving approachable ales with bold hop "
|
"Locally inspired brewery serving approachable ales with bold hop "
|
||||||
"character.",
|
"character.",
|
||||||
"Destination taproom known for balanced IPAs and cocoa-rich "
|
"Destination taproom known for balanced IPAs and cocoa-rich "
|
||||||
"stouts."};
|
"stouts."};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 18> kUsernames = {
|
static constexpr std::array<std::string_view, 18> kUsernames = {
|
||||||
"hopseeker", "malttrail", "yeastwhisper", "lagerlane",
|
"hopseeker", "malttrail", "yeastwhisper", "lagerlane",
|
||||||
"barrelbound", "foamfinder", "taphunter", "graingeist",
|
"barrelbound", "foamfinder", "taphunter", "graingeist",
|
||||||
"brewscout", "aleatlas", "caskcompass", "hopsandmaps",
|
"brewscout", "aleatlas", "caskcompass", "hopsandmaps",
|
||||||
"mashpilot", "pintnomad", "fermentfriend", "stoutsignal",
|
"mashpilot", "pintnomad", "fermentfriend", "stoutsignal",
|
||||||
"sessionwander", "kettlekeeper"};
|
"sessionwander", "kettlekeeper"};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 18> kBios = {
|
static constexpr std::array<std::string_view, 18> kBios = {
|
||||||
"Always chasing balanced IPAs and crisp lagers across local taprooms.",
|
"Always chasing balanced IPAs and crisp lagers across local taprooms.",
|
||||||
"Weekend brewery explorer with a soft spot for dark, roasty stouts.",
|
"Weekend brewery explorer with a soft spot for dark, roasty stouts.",
|
||||||
"Documenting tiny brewpubs, fresh pours, and unforgettable beer "
|
"Documenting tiny brewpubs, fresh pours, and unforgettable beer "
|
||||||
"gardens.",
|
"gardens.",
|
||||||
"Fan of farmhouse ales, food pairings, and long tasting flights.",
|
"Fan of farmhouse ales, food pairings, and long tasting flights.",
|
||||||
"Collecting favorite pilsners one city at a time.",
|
"Collecting favorite pilsners one city at a time.",
|
||||||
"Hops-first drinker who still saves room for classic malt-forward "
|
"Hops-first drinker who still saves room for classic malt-forward "
|
||||||
"styles.",
|
"styles.",
|
||||||
"Finding hidden tap lists and sharing the best seasonal releases.",
|
"Finding hidden tap lists and sharing the best seasonal releases.",
|
||||||
"Brewery road-tripper focused on local ingredients and clean "
|
"Brewery road-tripper focused on local ingredients and clean "
|
||||||
"fermentation.",
|
"fermentation.",
|
||||||
"Always comparing house lagers and ranking patio pint vibes.",
|
"Always comparing house lagers and ranking patio pint vibes.",
|
||||||
"Curious about yeast strains, barrel programs, and cellar experiments.",
|
"Curious about yeast strains, barrel programs, and cellar experiments.",
|
||||||
"Believes every neighborhood deserves a great community taproom.",
|
"Believes every neighborhood deserves a great community taproom.",
|
||||||
"Looking for session beers that taste great from first sip to last.",
|
"Looking for session beers that taste great from first sip to last.",
|
||||||
"Belgian ale enthusiast who never skips a new saison.",
|
"Belgian ale enthusiast who never skips a new saison.",
|
||||||
"Hazy IPA critic with deep respect for a perfectly clear pilsner.",
|
"Hazy IPA critic with deep respect for a perfectly clear pilsner.",
|
||||||
"Visits breweries for the stories, stays for the flagship pours.",
|
"Visits breweries for the stories, stays for the flagship pours.",
|
||||||
"Craft beer fan mapping tasting notes and favorite brew routes.",
|
"Craft beer fan mapping tasting notes and favorite brew routes.",
|
||||||
"Always ready to trade recommendations for underrated local breweries.",
|
"Always ready to trade recommendations for underrated local breweries.",
|
||||||
"Keeping a running list of must-try collab releases and tap "
|
"Keeping a running list of must-try collab releases and tap "
|
||||||
"takeovers."};
|
"takeovers."};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_MOCK_GENERATOR_H_
|
#endif // BIERGARTEN_PIPELINE_INCLUDES_DATA_GENERATION_MOCK_GENERATOR_H_
|
||||||
|
|||||||
Reference in New Issue
Block a user