Last active
June 23, 2017 22:01
-
-
Save 3v1n0/396a906d33c6082bec1e to your computer and use it in GitHub Desktop.
PizzaDough
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.2 | |
import QtQuick.Window 2.1 | |
import QtQuick.Controls 1.1 | |
Window | |
{ | |
id: main | |
visible: true | |
title: "Pizza Dough Helper" | |
Item | |
{ | |
id: units | |
function gu(val) { return val * 8; } | |
} | |
Item | |
{ | |
id: i18n | |
function tr(val) { return val; } | |
} | |
property var padding: units.gu(2) | |
width: units.gu(45) | |
height: units.gu(55) | |
ListModel | |
{ | |
id: recipes | |
ListElement { text: "Coppi 24h TA"; description: "Pizza al Piatto, 18+6"; | |
w: 1000; f: 1700; y: 0.5; s: 50; ft: 150; } | |
ListElement { text: "Verace"; description: "Impasto Napoletana STG, 2+6"; | |
w: 1000; f: 1750; y: 3.0; s: 50; ft: 0; } | |
ListElement { text: "Fratelli Salvo"; description: "Impasto Napoletana dei Salvo, 10+8"; | |
w: 1000; f: 1500; y: 1.0; s: 50; ft: 0; } | |
ListElement { text: "Sorbillo"; description: "Impasto Sorbillo, 8+6"; | |
w: 1000; f: 1750; y: 4.0; s: 58; ft: 0; } | |
ListElement { text: "Napoletana Jaws"; description: "Impasto Napoletana JAWS, 18+6"; | |
w: 1000; f: 1612; y: 1.0; s: 53; ft: 0; } | |
ListElement { text: "Napoletana Notturno Italiano"; description: "1+5"; | |
w: 1000; f: 1650; y: 8; s: 50; ft: 0; } | |
ListElement { text: "Napoletana Notturno Italiano"; description: "3+5"; | |
w: 1000; f: 1650; y: 3; s: 50; ft: 0; } | |
ListElement { text: "Scrocchiarella Jaws"; description: "Romana Tonda, 0+24 Frigo"; | |
w: 1000; f: 1695; y: 3; s: 50; ft: 50; } | |
ListElement { text: "Scrocchiarella giulieo65"; description: "Romana Tonda, 0.5+17+7 Frigo + TA"; | |
w: 266; f: 360; y: 0.8; s: 18; ft: 20; } | |
ListElement { text: "Scrocchiarella Oscor"; description: "Romana Tonda, 0.5+20 Frigo"; | |
w: 1000; f: 1750; y: 3; s: 60; ft: 50; } | |
ListElement { text: "Scrocchiarella paolour"; description: "Romana Tonda, 0+48 Frigo"; | |
w: 1000; f: 1695; y: 0.5; s: 0; ft: 200; } | |
ListElement { text: "Scrocchiarella FedeC87"; description: "Romana Tonda, 3+3"; | |
w: 1000; f: 1800; y: 24; s: 26; ft: 0; } | |
ListElement { text: "Scrocchiarella Giancarlo Stagliata"; description: "Romana Tonda, 0+6"; | |
w: 1000; f: 1800; y: 16; s: 32; ft: 20; | |
lnk: "http://laconfraternitadellapizza.forumfree.it/?t=72114425"; } | |
ListElement { text: "Scrocchiarella Giancarlo 24h"; description: "Romana Tonda, 20+4 Frigo"; | |
w: 1000; f: 1800; y: 2; s: 35; ft: 20; | |
lnk: "http://laconfraternitadellapizza.forumfree.it/?t=71679964"; } | |
ListElement { text: "Scrocchiarella Giancarlo Fast"; description: "Romana Tonda, 3+3"; | |
w: 1000; f: 1800; y: 4; s: 35; ft: 20; | |
lnk: "http://laconfraternitadellapizza.forumfree.it/?t=71679964"; } | |
ListElement { text: "Teglia 80%"; description: "Teglia alta idratazione, 20+4 Frigo"; | |
w: 800; f: 1000; y: 10; s: 20; ft: 30; } | |
ListElement { text: "Teglia 70%"; description: "Teglia alta idratazione, 20+4 Frigo"; | |
w: 700; f: 1000; y: 7; s: 20; ft: 30; } | |
function apply() | |
{ | |
var recipe = recipe_selector.model.get(recipe_selector.selectedIndex); | |
var ft = recipe.ft / (oiltoggle.oilmode ? 2.5 : 1) | |
var recipe_weight = recipe.w + recipe.f + recipe.y + recipe.s + ft | |
var multiplier = target.text / recipe_weight | |
description.text = recipe.description | |
flour.text = Math.round(recipe.f * multiplier) | |
h2o.text = Math.round(recipe.w * multiplier) | |
yeast.text = (recipe.y * multiplier).toFixed(2) | |
salt.text = (recipe.s * multiplier).toFixed(1) | |
fat.text = (ft * multiplier).toFixed(1) | |
} | |
} | |
Component.onCompleted: { recipes.apply(); } | |
Item | |
{ | |
x: main.padding | |
y: main.padding | |
width: parent.width - 2 * main.padding | |
height: parent.height - 2 * main.padding | |
Column | |
{ | |
spacing: main.padding | |
Label | |
{ | |
anchors.horizontalCenter: parent.horizontalCenter | |
text: i18n.tr("Get the recipe for your Pizza!") | |
font.pointSize: 16 | |
} | |
ComboBox | |
{ | |
id: recipe_selector | |
property alias selectedIndex: recipe_selector.currentIndex | |
width: parent.width | |
model: recipes | |
onSelectedIndexChanged: { recipes.apply(); } | |
} | |
Label | |
{ | |
id: description | |
anchors.horizontalCenter: parent.horizontalCenter | |
} | |
Grid | |
{ | |
spacing: main.padding | |
verticalItemAlignment: Grid.AlignVCenter | |
horizontalItemAlignment: Grid.AlignHCenter | |
columns: 3 | |
Text | |
{ | |
text: i18n.tr("Balls"); | |
} | |
TextField | |
{ | |
id: balls | |
inputMethodHints: Qt.ImhFormattedNumbersOnly | |
validator: IntValidator {} | |
// hasClearButton: false | |
text: "2" | |
onTextChanged: { target.text = ballSize.value.toFixed(0) * text } | |
} | |
Column | |
{ | |
Slider | |
{ | |
id: ballSize | |
width: units.gu(10) | |
minimumValue: 180 | |
maximumValue: 250 | |
value: 250 | |
// live: true | |
onValueChanged: { target.text = value.toFixed(0) * balls.text } | |
} | |
Label | |
{ | |
text: "Ball Weight: %1".arg(ballSize.value.toFixed(0)) | |
font.pointSize: 7 | |
} | |
} | |
Text | |
{ | |
text: i18n.tr("Weight Target"); | |
} | |
TextField | |
{ | |
id: target | |
inputMethodHints: Qt.ImhFormattedNumbersOnly | |
validator: DoubleValidator { decimals: 1 } | |
text: "1000" | |
// hasClearButton: false | |
onTextChanged: { recipes.apply(); } | |
Keys.onReleased: { if ((event.key >= Qt.Key_0 && event.key <= Qt.Key_9) || event.key == Qt.Key_Delete || event.key == Qt.Key_Backspace) { | |
balls.text = text / ballSize.value; | |
}} | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Flour"); | |
} | |
TextField | |
{ | |
id: flour | |
enabled: false | |
// hasClearButton: false | |
// color: "black" | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("H₂O"); | |
} | |
TextField | |
{ | |
id: h2o | |
enabled: false | |
// hasClearButton: false | |
// color: "black" | |
Label | |
{ | |
text: "ml" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Yeast"); | |
} | |
TextField | |
{ | |
id: yeast | |
enabled: false | |
// hasClearButton: false | |
// color: "black" | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Button | |
{ | |
id: yeastTricks | |
text: "Help" | |
onClicked: yeastPopover.createObject(main, {visible: true}) | |
Component { | |
id: yeastPopover | |
Window | |
{ | |
title: "Yeast tricks" | |
width: units.gu(41.25) | |
height: units.gu(3.75) | |
Item | |
{ | |
id: yeastFunctions | |
function computeYeastSolution() | |
{ | |
yeastSolution.text = (yeast.text * yeastWater.text / yeastPart.text).toFixed(0) | |
} | |
} | |
Component.onCompleted: { yeastFunctions.computeYeastSolution() } | |
Row | |
{ | |
spacing: units.gu(1) | |
TextField | |
{ | |
id: yeastSolution | |
enabled: false | |
// hasClearButton: false | |
width: units.gu(5.5) | |
// color: "black" | |
Label | |
{ | |
text: "ml" | |
font.pointSize: 8 | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: i18n.tr("of"); | |
} | |
TextField | |
{ | |
id: yeastWater | |
enabled: true | |
validator: IntValidator {} | |
// hasClearButton: false | |
width: units.gu(7) | |
text: "500" | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
onTextChanged: yeastFunctions.computeYeastSolution() | |
Label | |
{ | |
text: "ml" | |
font.pointSize: 8 | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: i18n.tr("H₂O +"); | |
} | |
TextField | |
{ | |
id: yeastPart | |
enabled: true | |
validator: IntValidator {} | |
// hasClearButton: false | |
width: units.gu(4.5) | |
text: "5" | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
onTextChanged: yeastFunctions.computeYeastSolution() | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8 | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: "yeast solution"; | |
} | |
} | |
} | |
} | |
} | |
Text | |
{ | |
text: i18n.tr("Salt"); | |
} | |
TextField | |
{ | |
id: salt | |
enabled: false | |
// hasClearButton: false | |
// color: "black" | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Fat"); | |
} | |
TextField | |
{ | |
id: fat | |
enabled: false | |
// hasClearButton: false | |
// color: "black" | |
Label | |
{ | |
text: "g" | |
font.pointSize: 8; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Button | |
{ | |
id: oiltoggle | |
property bool oilmode: true | |
text: i18n.tr(oilmode ? "Oil" : "Lard") | |
onClicked: { | |
oilmode = !oilmode | |
recipes.apply(); | |
} | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.1 | |
import Ubuntu.Components 0.1 | |
import Ubuntu.Components.Popups 0.1 | |
MainView | |
{ | |
id: main | |
applicationName: "Pizza Dough Helper" | |
useDeprecatedToolbar: false | |
readonly property var padding: units.gu(2) | |
width: units.gu(55) | |
height: units.gu(60) | |
ListModel | |
{ | |
id: recipes | |
ListElement { name: "Coppi 24h TA"; description: "Pizza al Piatto, 18+6"; | |
w: 1000; f: 1700; y: 0.5; s: 50; ft: 150; } | |
ListElement { name: "Verace"; description: "Impasto Napoletana STG, 2+6"; | |
w: 1000; f: 1750; y: 3.0; s: 50; ft: 0; } | |
ListElement { name: "Fratelli Salvo"; description: "Impasto Napoletana dei Salvo, 10+8"; | |
w: 1000; f: 1500; y: 1.0; s: 50; ft: 0; } | |
ListElement { name: "Sorbillo"; description: "Impasto Sorbillo, 8+6"; | |
w: 1000; f: 1750; y: 4.0; s: 58; ft: 0; } | |
ListElement { name: "Napoletana Jaws"; description: "Impasto Napoletana JAWS, 18+6"; | |
w: 1000; f: 1612; y: 1.0; s: 53; ft: 0; } | |
ListElement { name: "Napoletana Notturno Italiano"; description: "1+5"; | |
w: 1000; f: 1650; y: 8; s: 50; ft: 0; } | |
ListElement { name: "Scrocchiarella Jaws"; description: "Romana Tonda, 0+24 Frigo"; | |
w: 1000; f: 1695; y: 3; s: 50; ft: 50; } | |
ListElement { name: "Scrocchiarella giulieo65"; description: "Romana Tonda, 0.5+17+7 Frigo + TA"; | |
w: 266; f: 360; y: 0.8; s: 18; ft: 20; } | |
ListElement { name: "Scrocchiarella Oscor"; description: "Romana Tonda, 0.5+20 Frigo"; | |
w: 1000; f: 1750; y: 3; s: 60; ft: 50; } | |
ListElement { name: "Scrocchiarella paolour"; description: "Romana Tonda, 0+48 Frigo"; | |
w: 1000; f: 1695; y: 0.5; s: 0; ft: 200; } | |
ListElement { name: "Teglia 80%"; description: "Teglia alta idratazione, 20+4 Frigo"; | |
w: 800; f: 1000; y: 10; s: 20; ft: 30; } | |
ListElement { name: "Teglia 70%"; description: "Teglia alta idratazione, 20+4 Frigo"; | |
w: 700; f: 1000; y: 7; s: 20; ft: 30; } | |
function apply() | |
{ | |
var recipe = recipe_selector.model.get(recipe_selector.selectedIndex); | |
var ft = recipe.ft / (oiltoggle.oilmode ? 2.5 : 1) | |
var recipe_weight = recipe.w + recipe.f + recipe.y + recipe.s + ft | |
var multiplier = target.text / recipe_weight | |
flour.text = Math.round(recipe.f * multiplier) | |
h2o.text = Math.round(recipe.w * multiplier) | |
yeast.text = (recipe.y * multiplier).toFixed(2) | |
salt.text = (recipe.s * multiplier).toFixed(1) | |
fat.text = (ft * multiplier).toFixed(1) | |
} | |
} | |
Component.onCompleted: recipes.apply() | |
Flickable | |
{ | |
x: main.padding | |
y: main.padding | |
width: parent.width - 2 * main.padding | |
height: parent.height - 2 * main.padding | |
contentHeight: main_column.height | |
contentWidth: main_column.width | |
Column | |
{ | |
id: main_column | |
spacing: main.padding | |
Label | |
{ | |
anchors.horizontalCenter: parent.horizontalCenter | |
text: i18n.tr("Get the recipe for your Pizza!") | |
fontSize: "large" | |
} | |
OptionSelector | |
{ | |
id: recipe_selector | |
model: recipes | |
delegate: OptionSelectorDelegate { text: name; subText: description; } | |
onSelectedIndexChanged: { recipes.apply(); } | |
} | |
Grid | |
{ | |
spacing: main.padding | |
verticalItemAlignment: Grid.AlignVCenter | |
horizontalItemAlignment: Grid.AlignHCenter | |
columns: 3 | |
Text | |
{ | |
text: i18n.tr("Balls"); | |
} | |
TextField | |
{ | |
id: balls | |
inputMethodHints: Qt.ImhFormattedNumbersOnly | |
validator: IntValidator {} | |
hasClearButton: false | |
text: "2" | |
KeyNavigation.tab: target | |
KeyNavigation.backtab: target | |
onTextChanged: { target.text = ballSize.value.toFixed(0) * text } | |
} | |
Slider | |
{ | |
id: ballSize | |
width: units.gu(10) | |
minimumValue: 160 | |
maximumValue: 250 | |
value: 250 | |
live: true | |
onValueChanged: { target.text = value.toFixed(0) * balls.text } | |
Label | |
{ | |
text: "Ball Weight: %1".arg(parent.value.toFixed(0)) | |
fontSize: "x-small" | |
} | |
} | |
Text | |
{ | |
text: i18n.tr("Weight Target"); | |
} | |
TextField | |
{ | |
id: target | |
inputMethodHints: Qt.ImhFormattedNumbersOnly | |
validator: DoubleValidator { decimals: 1 } | |
text: "1000" | |
hasClearButton: false | |
onTextChanged: { recipes.apply(); } | |
KeyNavigation.tab: balls | |
KeyNavigation.backtab: balls | |
Keys.onReleased: { if ((event.key >= Qt.Key_0 && event.key <= Qt.Key_9) || event.key == Qt.Key_Delete || event.key == Qt.Key_Backspace) { | |
balls.text = text / ballSize.value; | |
}} | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Flour"); | |
} | |
TextField | |
{ | |
id: flour | |
enabled: false | |
hasClearButton: false | |
color: "black" | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("H₂O"); | |
} | |
TextField | |
{ | |
id: h2o | |
enabled: false | |
hasClearButton: false | |
color: "black" | |
Label | |
{ | |
text: "ml" | |
fontSize: "x-small"; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
color: parent.color | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Yeast"); | |
} | |
TextField | |
{ | |
id: yeast | |
enabled: false | |
hasClearButton: false | |
color: "black" | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Button | |
{ | |
id: yeastTricks | |
text: "Help" | |
onClicked: PopupUtils.open(yeastPopover, yeastTricks) | |
Component | |
{ | |
id: yeastPopover | |
Popover | |
{ | |
Component.onCompleted: yeastSolution.compute() | |
Row | |
{ | |
spacing: units.gu(1) | |
TextField | |
{ | |
id: yeastSolution | |
enabled: false | |
hasClearButton: false | |
width: units.gu(5.5) | |
color: "black" | |
function compute() | |
{ | |
text = (yeast.text * yeastWater.text / yeastPart.text).toFixed(0) | |
} | |
Label | |
{ | |
text: "ml" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: i18n.tr("of"); | |
} | |
TextField | |
{ | |
id: yeastWater | |
enabled: true | |
validator: IntValidator {} | |
hasClearButton: false | |
width: units.gu(7) | |
text: "500" | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
onTextChanged: yeastSolution.compute() | |
KeyNavigation.tab: yeastPart | |
Label | |
{ | |
text: "ml" | |
fontSize: "x-small"; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: i18n.tr("H₂O +"); | |
} | |
TextField | |
{ | |
id: yeastPart | |
enabled: true | |
validator: IntValidator {} | |
hasClearButton: false | |
width: units.gu(4.5) | |
text: "5" | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
onTextChanged: yeastSolution.compute() | |
KeyNavigation.tab: yeastWater | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Label | |
{ | |
anchors.verticalCenter: yeastSolution.verticalCenter | |
text: "yeast solution"; | |
} | |
} | |
} | |
} | |
} | |
Text | |
{ | |
text: i18n.tr("Salt"); | |
} | |
TextField | |
{ | |
id: salt | |
enabled: false | |
hasClearButton: false | |
color: "black" | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Item { width:1; height:1 } | |
Text | |
{ | |
text: i18n.tr("Fat"); | |
} | |
TextField | |
{ | |
id: fat | |
enabled: false | |
hasClearButton: false | |
color: "black" | |
Label | |
{ | |
text: "g" | |
fontSize: "x-small"; | |
color: parent.color | |
anchors.right: parent.right | |
anchors.bottom: parent.bottom | |
anchors.rightMargin: units.gu(0.5) | |
anchors.bottomMargin: units.gu(0.5) | |
} | |
} | |
Button | |
{ | |
id: oiltoggle | |
property bool oilmode: true | |
text: i18n.tr(oilmode ? "Oil" : "Lard") | |
gradient: oilmode ? UbuntuColors.greyGradient : null | |
onClicked: { | |
oilmode = !oilmode | |
recipes.apply(); | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment