import%20marimo%0A%0A__generated_with%20%3D%20%220.25.0%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20METADATA%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22id%22%3A%20%22log_loss%22%2C%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%22From%20Bernoulli%20to%20Log%20Loss%22%2C%0A%20%20%20%20%20%20%20%20%22kind%22%3A%20%22concept%22%2C%0A%20%20%20%20%20%20%20%20%22difficulty%22%3A%20%22beginner%22%2C%0A%20%20%20%20%20%20%20%20%22status%22%3A%20%22complete%22%2C%0A%20%20%20%20%20%20%20%20%22topics%22%3A%20%5B%22probability%22%2C%20%22likelihood%22%2C%20%22loss_functions%22%5D%2C%0A%20%20%20%20%20%20%20%20%22related_models%22%3A%20%5B%5D%2C%0A%20%20%20%20%20%20%20%20%22prerequisites%22%3A%20%5B%5D%2C%0A%20%20%20%20%7D%0A%20%20%20%20mo.md(f%22%23%20%7BMETADATA%5B'name'%5D%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20result%20we%20want%20to%20explain%0A%0A%20%20%20%20Log%20loss%20is%20the%20negative%20average%20log-probability%20assigned%20to%20the%20labels%20that%20actually%20occurred.%0A%0A%20%20%20%20%23%23%20One%20probability%20must%20explain%20the%20observed%20label%0A%0A%20%20%20%20A%20binary%20prediction%20assigns%20a%20probability%20%24%5Chat%20p%24%20to%20label%20%241%24.%20How%20should%20that%20probability%20be%20scored%20after%20the%20true%20label%20is%20observed%3F%0A%0A%20%20%20%20The%20answer%20follows%20one%20short%20chain%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Ctext%7BBernoulli%7D%0A%20%20%20%20%5Clongrightarrow%0A%20%20%20%20%5Ctext%7Blikelihood%7D%0A%20%20%20%20%5Clongrightarrow%0A%20%20%20%20%5Ctext%7Blog-likelihood%7D%0A%20%20%20%20%5Clongrightarrow%0A%20%20%20%20%5Ctext%7Blog%20loss%7D%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%20Why%20the%20derivation%20matters%0A%0A%20%20%20%20The%20derivation%20explains%20why%20log%20loss%20rewards%20probability%20assigned%20to%20the%20observed%20result%20and%20strongly%20penalizes%20confident%20mistakes.%0A%0A%20%20%20%20%23%23%20Roadmap%20of%20the%20derivation%0A%0A%20%20%20%20**Question%3A**%20how%20does%20the%20probability%20of%20each%20observed%20label%20become%20one%20loss%20for%20the%20entire%20dataset%3F%0A%0A%20%20%20%20%23%23%20What%20the%20symbols%20mean%0A%0A%20%20%20%20%7C%20Symbol%20%7C%20Meaning%20%7C%0A%20%20%20%20%7C---%7C---%7C%0A%20%20%20%20%7C%20%24y%5Cin%5C%7B0%2C1%5C%7D%24%20%7C%20observed%20label%20%7C%0A%20%20%20%20%7C%20%24%5Chat%20p%24%20%7C%20predicted%20probability%20that%20%24y%3D1%24%20%7C%0A%20%20%20%20%7C%20%241-%5Chat%20p%24%20%7C%20predicted%20probability%20that%20%24y%3D0%24%20%7C%0A%20%20%20%20%7C%20%24n%24%20%7C%20number%20of%20examples%20%7C%0A%0A%20%20%20%20This%20lesson%20starts%20from%20%24%5Chat%20p%24.%20How%20a%20score%20is%20converted%20into%20a%20probability%20is%20a%20separate%20topic.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Bernoulli%20selects%20the%20observed%20label%0A%0A%20%20%20%20A%20Bernoulli%20variable%20has%20two%20possible%20outcomes%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20P(Y%3D1)%3Dp%2C%0A%20%20%20%20%5Cqquad%0A%20%20%20%20P(Y%3D0)%3D1-p.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Both%20cases%20fit%20into%20one%20expression%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7BP(Y%3Dy)%3Dp%5Ey(1-p)%5E%7B1-y%7D%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20exponents%20act%20like%20switches.%0A%0A%20%20%20%20If%20%24y%3D1%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20p%5E1(1-p)%5E0%3Dp.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20If%20%24y%3D0%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20p%5E0(1-p)%5E1%3D1-p.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Therefore%2C%20after%20a%20prediction%20%24%5Chat%20p%24%20and%20an%20observed%20label%20%24y%24%2C%20the%20probability%20assigned%20to%20what%20happened%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20P(Y%3Dy)%3D%5Chat%20p%5Ey(1-%5Chat%20p)%5E%7B1-y%7D%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%23%20One%20example%0A%0A%20%20%20%20Suppose%20%24%5Chat%20p%3D0.8%24.%0A%0A%20%20%20%20-%20If%20%24y%3D1%24%2C%20the%20prediction%20assigned%20probability%20%240.8%24%20to%20the%20observed%20result.%0A%20%20%20%20-%20If%20%24y%3D0%24%2C%20it%20assigned%20probability%20%241-0.8%3D0.2%24%20to%20the%20observed%20result.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20labels%20%3D%20%5B1%2C%200%2C%201%5D%0A%20%20%20%20predictions%20%3D%20%5B0.9%2C%200.2%2C%200.7%5D%0A%20%20%20%20observed_probabilities%20%3D%20%5B%0A%20%20%20%20%20%20%20%20prediction%20if%20label%20%3D%3D%201%20else%201%20-%20prediction%0A%20%20%20%20%20%20%20%20for%20label%2C%20prediction%20in%20zip(labels%2C%20predictions)%0A%20%20%20%20%5D%0A%20%20%20%20for%20label%2C%20prediction%2C%20observed%20in%20zip(labels%2C%20predictions%2C%20observed_probabilities)%3A%0A%20%20%20%20%20%20%20%20print(f%22y%3D%7Blabel%7D%2C%20p_hat%3D%7Bprediction%3A.1f%7D%20-%3E%20probability%20of%20observed%20label%3D%7Bobserved%3A.1f%7D%22)%0A%20%20%20%20return%20(observed_probabilities%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%202.%20Likelihood%20combines%20the%20dataset%0A%0A%20%20%20%20For%20%24n%24%20independent%20observations%2C%20multiply%20the%20probability%20assigned%20to%20every%20observed%20label%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Cmathcal%7BV%7D%0A%20%20%20%20%3D%5Cprod_%7Bi%3D1%7D%5E%7Bn%7D%0A%20%20%20%20%5Chat%20p_i%5E%7By_i%7D(1-%5Chat%20p_i)%5E%7B1-y_i%7D%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%24%5Cmathcal%7BV%7D%24%20is%20the%20**likelihood**%20of%20the%20observed%20dataset.%20A%20larger%20likelihood%20means%20that%20the%20predictions%20collectively%20assigned%20more%20probability%20to%20what%20actually%20happened.%0A%0A%20%20%20%20%23%23%23%20Three%20examples%0A%0A%20%20%20%20Suppose%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20(y_1%2Cy_2%2Cy_3)%3D(1%2C0%2C1)%0A%20%20%20%20%24%24%0A%0A%20%20%20%20and%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20(%5Chat%20p_1%2C%5Chat%20p_2%2C%5Chat%20p_3)%3D(0.9%2C0.2%2C0.7).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20probabilities%20assigned%20to%20the%20observed%20labels%20are%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%200.9%2C%5Cqquad%201-0.2%3D0.8%2C%5Cqquad%200.7.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20So%20the%20likelihood%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathcal%7BV%7D%3D0.9%5Ctimes0.8%5Ctimes0.7%3D0.504.%0A%20%20%20%20%24%24%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(observed_probabilities)%3A%0A%20%20%20%20likelihood%20%3D%201.0%0A%20%20%20%20for%20observed_probability%20in%20observed_probabilities%3A%0A%20%20%20%20%20%20%20%20likelihood%20*%3D%20observed_probability%0A%20%20%20%20print(f%22likelihood%20%3D%20%7B'%20%C3%97%20'.join(map(str%2C%20observed_probabilities))%7D%20%3D%20%7Blikelihood%3A.3f%7D%22)%0A%20%20%20%20return%20(likelihood%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20The%20logarithm%20turns%20the%20product%20into%20a%20sum%0A%0A%20%20%20%20A%20product%20of%20many%20probabilities%20becomes%20extremely%20small.%20The%20logarithm%20gives%20an%20equivalent%20but%20easier%20expression%20because%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Clog(ab)%3D%5Clog%20a%2B%5Clog%20b.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Applying%20it%20to%20the%20likelihood%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Baligned%7D%0A%20%20%20%20%5Clog%5Cmathcal%7BV%7D%0A%20%20%20%20%26%3D%5Clog%5Cprod_%7Bi%3D1%7D%5E%7Bn%7D%0A%20%20%20%20%5Chat%20p_i%5E%7By_i%7D(1-%5Chat%20p_i)%5E%7B1-y_i%7D%5C%5C%0A%20%20%20%20%26%3D%5Cboxed%7B%0A%20%20%20%20%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%0A%20%20%20%20%5Cleft%5By_i%5Clog%5Chat%20p_i%2B(1-y_i)%5Clog(1-%5Chat%20p_i)%5Cright%5D%0A%20%20%20%20%7D.%0A%20%20%20%20%5Cend%7Baligned%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20This%20is%20the%20**log-likelihood**.%20Because%20%24%5Clog%24%20is%20increasing%2C%20the%20predictions%20that%20maximize%20likelihood%20also%20maximize%20log-likelihood.%0A%0A%20%20%20%20For%20the%20three-example%20dataset%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Clog%5Cmathcal%7BV%7D%3D%5Clog(0.504)%5Capprox-0.685.%0A%20%20%20%20%24%24%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(likelihood%2C%20observed_probabilities)%3A%0A%20%20%20%20import%20math%0A%0A%20%20%20%20log_likelihood%20%3D%20sum(math.log(value)%20for%20value%20in%20observed_probabilities)%0A%20%20%20%20print(f%22sum%20of%20log%20probabilities%20%3D%20%7Blog_likelihood%3A.3f%7D%22)%0A%20%20%20%20print(f%22log%20of%20their%20product%20%20%20%20%20%20%3D%20%7Bmath.log(likelihood)%3A.3f%7D%22)%0A%20%20%20%20return%20(log_likelihood%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20The%20negative%20sign%20creates%20a%20loss%0A%0A%20%20%20%20Likelihood%20should%20be%20maximized.%20A%20loss%20should%20be%20minimized.%20Taking%20the%20negative%20changes%20one%20problem%20into%20the%20other.%0A%0A%20%20%20%20Taking%20the%20mean%20gives%20the%20average%20loss%20per%20example%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20J%0A%20%20%20%20%3D-%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%0A%20%20%20%20%5Cleft%5B%0A%20%20%20%20y_i%5Clog%5Chat%20p_i%0A%20%20%20%20%2B(1-y_i)%5Clog(1-%5Chat%20p_i)%0A%20%20%20%20%5Cright%5D%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20This%20is%20**binary%20log%20loss**%2C%20also%20called%20**binary%20cross-entropy**.%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Ctext%7Bmaximize%20likelihood%7D%0A%20%20%20%20%5Ciff%0A%20%20%20%20%5Ctext%7Bmaximize%20log-likelihood%7D%0A%20%20%20%20%5Ciff%0A%20%20%20%20%5Ctext%7Bminimize%20log%20loss%7D%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20For%20the%20three-example%20dataset%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20J%3D-%5Cfrac%7B1%7D%7B3%7D%5Clog(0.504)%5Capprox0.228.%0A%20%20%20%20%24%24%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(log_likelihood%2C%20observed_probabilities)%3A%0A%20%20%20%20mean_log_loss%20%3D%20-log_likelihood%20%2F%20len(observed_probabilities)%0A%20%20%20%20print(f%22mean%20log%20loss%20%3D%20-(%7Blog_likelihood%3A.3f%7D)%20%2F%20%7Blen(observed_probabilities)%7D%20%3D%20%7Bmean_log_loss%3A.3f%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%205.%20A%20confident%20mistake%20has%20a%20large%20loss%0A%0A%20%20%20%20For%20one%20example%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20L(%5Chat%20p%2Cy)%3D%0A%20%20%20%20%5Cbegin%7Bcases%7D%0A%20%20%20%20-%5Clog%5Chat%20p%2C%26y%3D1%2C%5C%5C%0A%20%20%20%20-%5Clog(1-%5Chat%20p)%2C%26y%3D0.%0A%20%20%20%20%5Cend%7Bcases%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20If%20the%20observed%20label%20is%20%24y%3D1%24%3A%0A%0A%20%20%20%20%7C%20Prediction%20%24%5Chat%20p%24%20%7C%20Loss%20%7C%20Meaning%20%7C%0A%20%20%20%20%7C---%3A%7C---%3A%7C---%7C%0A%20%20%20%20%7C%20%240.9%24%20%7C%20%240.105%24%20%7C%20correct%20and%20confident%20%7C%0A%20%20%20%20%7C%20%240.5%24%20%7C%20%240.693%24%20%7C%20uncertain%20%7C%0A%20%20%20%20%7C%20%240.1%24%20%7C%20%242.303%24%20%7C%20wrong%20and%20confident%20%7C%0A%20%20%20%20%7C%20%240.01%24%20%7C%20%244.605%24%20%7C%20very%20wrong%20and%20very%20confident%20%7C%0A%0A%20%20%20%20As%20%24%5Chat%20p%5Cto0%24%20while%20%24y%3D1%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20-%5Clog%5Chat%20p%5Cto%2B%5Cinfty.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Log%20loss%20asks%20more%20than%20%E2%80%9Cwas%20the%20final%20class%20correct%3F%E2%80%9D%20It%20asks%20%E2%80%9Chow%20much%20probability%20was%20assigned%20to%20the%20result%20that%20occurred%3F%E2%80%9D%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20probability%20%3D%20np.linspace(0.001%2C%200.999%2C%20500)%0A%20%20%20%20loss_when_one%20%3D%20-np.log(probability)%0A%20%20%20%20loss_when_zero%20%3D%20-np.log(1%20-%20probability)%0A%0A%20%20%20%20fig%2C%20ax%20%3D%20plt.subplots(figsize%3D(9%2C%204.2)%2C%20facecolor%3D%22%23FAF7F0%22)%0A%20%20%20%20ax.set_facecolor(%22%23FAF7F0%22)%0A%20%20%20%20ax.plot(probability%2C%20loss_when_one%2C%20color%3D%22%23E76F51%22%2C%20linewidth%3D2.5%2C%20label%3Dr%22observed%20%24y%3D1%24%22)%0A%20%20%20%20ax.plot(probability%2C%20loss_when_zero%2C%20color%3D%22%234C78A8%22%2C%20linewidth%3D2.5%2C%20label%3Dr%22observed%20%24y%3D0%24%22)%0A%20%20%20%20ax.axvline(0.5%2C%20color%3D%22%238D99AE%22%2C%20linestyle%3D%22--%22%2C%20linewidth%3D1)%0A%20%20%20%20ax.set(%0A%20%20%20%20%20%20%20%20title%3D%22Log%20loss%20scores%20the%20probability%20assigned%20to%20the%20observed%20label%22%2C%0A%20%20%20%20%20%20%20%20xlabel%3Dr%22predicted%20probability%20%24%5Chat%20p%24%20for%20label%201%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22loss%22%2C%0A%20%20%20%20%20%20%20%20xlim%3D(0%2C%201)%2C%0A%20%20%20%20%20%20%20%20ylim%3D(0%2C%207)%2C%0A%20%20%20%20)%0A%20%20%20%20ax.grid(color%3D%22%23DCE3E8%22%2C%20linewidth%3D0.8)%0A%20%20%20%20ax.set_axisbelow(True)%0A%20%20%20%20ax.spines%5B%5B%22top%22%2C%20%22right%22%5D%5D.set_visible(False)%0A%20%20%20%20ax.legend(frameon%3DFalse)%0A%20%20%20%20plt.tight_layout()%0A%20%20%20%20fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Do%20not%20confuse%20probability%20and%20decision%0A%0A%20%20%20%20Likelihood%20is%20not%20a%20second%20kind%20of%20probability%20distribution.%20The%20observed%20data%20are%20fixed%3B%20likelihood%20is%20the%20score%20obtained%20while%20comparing%20different%20predictions%20or%20parameter%20values.%0A%0A%20%20%20%20%23%23%20Read%20the%20loss%20through%20concrete%20probabilities%0A%0A%20%20%20%20For%20each%20example%2C%20first%20select%20the%20probability%20of%20the%20observed%20label%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20q_i%3D%0A%20%20%20%20%5Cbegin%7Bcases%7D%0A%20%20%20%20%5Chat%20p_i%2C%26y_i%3D1%2C%5C%5C%0A%20%20%20%201-%5Chat%20p_i%2C%26y_i%3D0.%0A%20%20%20%20%5Cend%7Bcases%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Then%20the%20entire%20derivation%20becomes%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cboxed%7B%0A%20%20%20%20%5Cmathcal%7BV%7D%3D%5Cprod_i%20q_i%2C%0A%20%20%20%20%5Cqquad%0A%20%20%20%20%5Clog%5Cmathcal%7BV%7D%3D%5Csum_i%5Clog%20q_i%2C%0A%20%20%20%20%5Cqquad%0A%20%20%20%20J%3D-%5Cfrac1n%5Csum_i%5Clog%20q_i%0A%20%20%20%20%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20If%20these%20three%20expressions%20are%20clear%2C%20the%20full%20derivation%20is%20clear%3A%20select%2C%20multiply%2C%20take%20the%20log%2C%20and%20negate%20the%20mean.%0A%0A%20%20%20%20%23%23%20What%20to%20remember%0A%0A%20%20%20%20For%20binary%20probability%20predictions%2C%20score%20the%20probability%20assigned%20to%20the%20observed%20label%E2%80%94not%20merely%20the%20class%20chosen%20by%20a%20threshold.%0A%0A%20%20%20%20%23%23%20Previous%20and%20next%0A%0A%20%20%20%20-%20Previous%3A%20%5BThe%20Perceptron%5D(%2Fconcepts%2Fperceptron)%20explains%20how%20a%20binary%20decision%20is%20formed.%0A%20%20%20%20-%20Next%3A%20%5BLoss%20and%20Optimization%5D(%2Fconcepts%2Floss_optimization)%20explains%20how%20an%20objective%20is%20minimized.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
4d41715c7c5dbeaf9e42d6723aec365a