To be able to edit code and run cells, you need to run the notebook yourself. Where would you like to run the notebook?

This notebook takes about 30 seconds to run.

In the cloud (experimental)

Binder is a free, open source service that runs scientific notebooks in the cloud! It will take a while, usually 2-7 minutes to get a session.

On your computer

(Recommended if you want to store your changes.)

  1. Copy the notebook URL:
  2. Run Pluto

    (Also see: How to install Julia and Pluto)

  3. Paste URL in the Open box

Frontmatter

If you are publishing this notebook on the web, you can set the parameters below to provide HTML metadata. This is useful for search engines and social media.

Author 1
👀 Reading hidden code
begin
import Pluto
import UUIDs: UUID
import Distributed
using PlutoUI
using DataFrames
import CSV
end
7.4 s
true
👀 Reading hidden code
let
function solution_pascal(n)
if n <= 1
[1.0]
else
prev = solution_pascal(n - 1)
0.5 * ([prev..., 0] .+ [0, prev...])
end
end

function solution_gaussian_kernel(n)
end

K[1] < K[5] < K[9] > K[13] > K[17]
end
710 ms

Part 1: autograding

👀 Reading hidden code
164 μs

Step 1: Select submission files

👀 Reading hidden code
167 μs

You need to write some code that returns the absolute paths to the students' homework submissions. The following code works for me, but probably not for you.

👀 Reading hidden code
228 μs
Error message

IOError: readdir("/home/fons/disorganised-mess/autograding/submissions/"): no such file or directory (ENOENT)

Stack trace

Here is what happened, the most recent locations are first:

  1. uv_error
  2. readdir(dir::String; join::Bool, sort::Bool)
  3. submission_files = let	all = readdir("/home/fons/disorganised-mess/autograding/submissions/"; join=true)	filter(f -> endswith(f, ".jl"), all)
submission_files = let
all = readdir("/home/fons/disorganised-mess/autograding/submissions/"; join=true)
filter(f -> endswith(f, ".jl"), all)
end
👀 Reading hidden code
---

It should return an arrays of strings, something like:

👀 Reading hidden code
182 μs
👀 Reading hidden code
12.7 μs
Error message

Another cell defining submission_files contains errors.

C'est la vie !
if !all(isabspath, submission_files)
md"""
!!! warning
Submission paths need to be _absolute_
"""
end
👀 Reading hidden code
---

Step 2: autograde actions

👀 Reading hidden code
166 μs

I have already written these, you can ignore this.

👀 Reading hidden code
174 μs
👀 Reading hidden code
48.2 ms
all (generic function with 11 methods)
all
👀 Reading hidden code
8.3 μs
107.5
sum(actions) do action
try
action.points_value
catch
0
end
end
👀 Reading hidden code
20.0 ms
Error message

UndefVarError: HTMLTable not defined

Stack trace

Here is what happened, the most recent locations are first:

  1. HTMLTable(autograde_results_df)
HTMLTable(autograde_results_df)
👀 Reading hidden code
---

Step 3: autograde all notebooks

👀 Reading hidden code
163 μs
Error message

Another cell defining submission_files contains errors.

md"**Click to start running the notebooks:**

$(@bind run_notebooks CheckBox()) run $(length(submission_files)) notebooks

---"
👀 Reading hidden code
---
pluto_session = Pluto.ServerSession(;options=Pluto.Configuration.from_flat_kwargs(
launch_browser=false,
require_secret_for_open_links=false,
require_secret_for_access=false,
workspace_use_distributed=false,
port=2468,
))
👀 Reading hidden code
218 ms
submission_files_to_run = run_notebooks ? Pluto.tamepath.(submission_files) : String[]
👀 Reading hidden code
207 μs
Pluto
Pluto
👀 Reading hidden code
8.8 μs
notebooks = let
for nb in values(pluto_session.notebooks)
Pluto.SessionActions.shutdown(pluto_session, nb)
end
map(submission_files_to_run) do path
nb = Pluto.load_notebook(Pluto.tamepath(path))
pluto_session.notebooks[nb.notebook_id] = nb
Pluto.update_save_run!(pluto_session, nb, nb.cells; run_async=false, prerender_text=true)
nb
end
end
👀 Reading hidden code
107 μs
autograde_results = map(notebooks) do nb
map(actions) do action
do_action(nb, action)
end
end
👀 Reading hidden code
26.9 ms
👀 Reading hidden code
74.4 μs
(This table has no columns)
(This table has no rows)
👀 Reading hidden code
414 ms
👀 Reading hidden code
425 ms

Part 2: manual review

👀 Reading hidden code
169 μs

Step 1: start notebook server

👀 Reading hidden code
766 μs

Click to start notebook server:

run notebook server


👀 Reading hidden code
941 μs
if run_server
@async Pluto.run(pluto_session)
md"> Server is running at [https://localhost:2468](https://localhost:2468)"
end
👀 Reading hidden code
4.9 ms

Step 2: manual grade actions

👀 Reading hidden code
186 μs
👀 Reading hidden code
36.3 ms
53
👀 Reading hidden code
7.7 ms

Step 3: select notebook

👀 Reading hidden code
165 μs
Error message

BoundsError: attempt to access 0-element Vector{Pair} at index [1]

Stack trace

Here is what happened, the most recent locations are first:

  1. getindex
  2. first(a::Vector{Pair})
  3. get(select::PlutoUI.BuiltinsNotebook.Select)
  4. macro expansion
  5. Show more...
uhmmmmmm??!
@bind inspected_notebook_index_str Select([string(i) => nb.path for (i,nb) in enumerate(notebooks)])
👀 Reading hidden code
---

Autograde results for selected homework

👀 Reading hidden code
174 μs
Error message

Another cell defining inspected_notebook_index_str contains errors.

autograde_results_df[inspected_notebook_index, :]
👀 Reading hidden code
---

Editable view of selected homework

👀 Reading hidden code
202 μs
👀 Reading hidden code
257 μs

Manual grading

👀 Reading hidden code
164 μs

Currently stored grades for this notebook:

👀 Reading hidden code
176 μs
Error message

Another cell defining inspected_notebook_index_str and inspected_manual_results contains errors.

if inspected_manual_results === missing
get(manual_results_dict, basename(inspected_notebook.path),
md"_Scores for this homework are not yet saved._"
)
else
inspected_manual_results
end
👀 Reading hidden code
---
Error message

Another cell defining inspected_notebook_index_str contains errors.

# struct ManualCheckAction <: GradingAction
# name
# points_value::Number
# rubric
# end
begin
inspected_notebook
manual_results_dict
@bind inspected_manual_results let
boxes = map(enumerate(manual)) do (i,action)
"""<tr>
<td><input type='number' id='field$(i)' min=0 max=$(action.points_value) step=1 value=$(action.points_value)><code> / $(action.points_value)</code></td>
<td>$(repr(MIME"text/html"(), action.rubric))</td>
</tr>"""
end
"""
<div id="hello">
<table>
<tbody>
$(join(boxes))
</tbody>
</table>
<input type="submit" value="Save!">
</div>

<style>
div#hello table td {
text-align: left;
}
div#hello table input[type=number] {
width: 4em;
text-align: center;
}
</style>
<script>
const div = this.querySelector("#hello")
const table = div.querySelector("table")
const inputs = table.querySelectorAll("input")
const update_value = () => {
//div.value = Object.fromEntries(Array.from(inputs).map((b) => [b.id, b.value]))
div.value = Array.from(inputs).map((b) => Number(b.value))
}
inputs.forEach(el => {
el.oninput = (e) => {
update_value()
e.stopPropagation()
}
})
const submit = div.querySelector("input[type=submit]")
submit.onclick = () => {
update_value()
div.dispatchEvent(new CustomEvent("input", {}))
}

</script>
""" |> HTML
end
end
👀 Reading hidden code
---
👀 Reading hidden code
42.5 ms
👀 Reading hidden code
21.3 μs
Error message

Another cell defining inspected_notebook_index_str and inspected_notebook contains errors.

manual_results_df = DataFrame(map(enumerate(collect(updated_manual_results_dict))) do (i,(filename, results))
(;
map(zip(manual, results)) do (action, result)
Symbol(displayname(action)) => result
end...,
autograde_results_df[1,:]...,
)
end)
👀 Reading hidden code
---
Error message

Another cell defining inspected_notebook_index_str and inspected_notebook contains errors.

DownloadButton(sprint(CSV.write, manual_results_df), "manual_results.csv")
👀 Reading hidden code
---
👀 Reading hidden code
68.5 μs
Error message

Another cell defining inspected_notebook_index_str and inspected_notebook contains errors.

# reactively add the result to our Dict
updated_manual_results_dict = let
if inspected_manual_results !== missing
manual_results_dict[inspected_notebook_index] = inspected_manual_results
end
manual_results_dict
end
👀 Reading hidden code
---
Error message

Another cell defining inspected_notebook_index_str contains errors.

inspected_notebook_index = parse(Int, inspected_notebook_index_str)
👀 Reading hidden code
---
Error message

Another cell defining inspected_notebook_index_str contains errors.

Keep calm, you got this!
inspected_notebook = notebooks[inspected_notebook_index]
👀 Reading hidden code
---

Appendix

👀 Reading hidden code
206 μs

Grading actions

👀 Reading hidden code
165 μs
abstract type GradingAction end
👀 Reading hidden code
318 μs
struct AutoTestAction <: GradingAction
name
points_value::Number
test::Expr
end
👀 Reading hidden code
1.4 ms
struct GetValue <: GradingAction
name
getter::Expr
end
👀 Reading hidden code
1.2 ms
ManualScoreAction
begin
struct ManualScoreAction <: GradingAction
name
points_value::Number
rubric
end
ManualScoreAction(name, points_value) = ManualScoreAction(name, points_valie, name)
end
👀 Reading hidden code
1.6 ms
ManualCheckAction
begin
struct ManualCheckAction <: GradingAction
name
points_value::Number
rubric
end
ManualCheckAction(name, points_value) = ManualCheckAction(name, points_valie, name)
end
👀 Reading hidden code
1.6 ms
do_action (generic function with 2 methods)
begin
function do_action(notebook::Pluto.Notebook, action::AutoTestAction)
tester = quote
try
$(action.test)
catch
false
end
end
if eval_in_notebook(notebook, tester) === true
action.points_value
else
zero(action.points_value)
end
end
function do_action(notebook::Pluto.Notebook, action::GetValue)
eval_in_notebook(notebook, action.getter)
end
end
👀 Reading hidden code
1.1 ms
displayname (generic function with 1 method)
begin
# default
displayname(action::GradingAction) = action.name
end
👀 Reading hidden code
375 μs

Misc

👀 Reading hidden code
162 μs
eval_in_notebook (generic function with 1 method)
function eval_in_notebook(notebook::Pluto.Notebook, expr)
ws = Pluto.WorkspaceManager.get_workspace((pluto_session, notebook))
fetcher = :(Core.eval($(ws.module_name), $(expr |> QuoteNode)))
Distributed.remotecall_eval(Main, ws.pid, fetcher)
end
👀 Reading hidden code
747 μs

Not used

👀 Reading hidden code
183 μs
struct GradedStudent
name
email
grader
end
👀 Reading hidden code
904 μs
""
👀 Reading hidden code
9.6 μs
Error message

MethodError: no method matching Main.workspace#3.GradedStudent(::SubString{String})

Closest candidates are:

Main.workspace#3.GradedStudent(::Any, ::Any, ::Any) at ~/work/disorganised-mess/disorganised-mess/autograding/updated.jl#==#0796b462-f85c-11ea-1bf2-53ad24ec447c:2

Stack trace

Here is what happened, the most recent locations are first:

  1. anonymous function
    graders = map(split(graders_raw, '\n')) do line	GradedStudent(split(line, '\t')...)end
  2. Show more...
graders = map(split(graders_raw, '\n')) do line
GradedStudent(split(line, '\t')...)
end
👀 Reading hidden code
---