Advice Media · Software Engineer
Updated · 2026-09-24

Advice Media Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

A Software Engineer at Advice Media plays a pivotal role in bridging the gap between sophisticated digital marketing technology and the practical needs of medical practices. This position is not merely about writing code; it is about crafting high-performance digital experiences that help clients grow their businesses and connect with patients. You will be responsible for building, maintaining, and optimizing the platforms that power Advice Media's client-facing solutions.

Find out what you will be typing into. A shared plain-text editor with no autocomplete, compiler or test runner changes what you have to hold in your head, and practising inside your own configured environment hides exactly that gap.

Advice Media candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.

Cut live latency without starving the bufferExpire rights across cached and offline copiesSessionise at-least-once heartbeats into exactly-once plays

38 min read

Browse Software Engineer questions

See the practice prompts

13Practice promptsAcross five skill areas
3With worked solutionsIncluded in the practice prompts

A Software Engineer at Advice Media plays a pivotal role in bridging the gap between sophisticated digital marketing technology and the practical needs of medical practices. This position is not merely about writing code; it is about crafting high-performance digital experiences that help clients grow their businesses and connect with patients. You will be responsible for building, maintaining, and optimizing the platforms that power Advice Media's client-facing solutions.

The work is characterized by a blend of technical depth and creative problem-solving. Whether you are focusing on front-end aesthetics to improve user engagement or back-end architecture to ensure system reliability, your contributions directly influence the success of Advice Media's clients. You will often work in collaborative, cross-functional environments where your ability to communicate technical concepts to non-technical stakeholders is just as important as your ability to ship clean, efficient code.

Advice Media values practitioners who can demonstrate both technical proficiency and a genuine interest in the business outcomes of their work. Be prepared to discuss how your technical decisions positively impact end-users.

01

Recruiter Conversation

reported

The person on this call usually cannot evaluate your code and does not need to. They write a short paragraph, and that paragraph is what a hiring manager skims when deciding who to put on your loop. So the test is not whether your work was hard, it is whether a non-engineer can repeat it correctly. Name systems by what they did rather than by their internal codename, give each project a shape (what was breaking, what you changed, what happened after), and keep the whole walkthrough near ninety seconds. Depth that cannot survive a paraphrase reads as vagueness.

What to demonstrate

  • Whether a non-engineer can restate your projects without distorting them, since their paraphrase is what travels to the hiring manager, not your sentences
  • Whether each project has a shape rather than a stack list: the failure or constraint, the change you made, the result and how it was measured
  • Whether you can say what was yours inside a team project without either inflating it or disappearing into the plural

How to prepare

  • Rewrite each headline project as two sentences with no internal system names and no acronyms outside your company, then say them to someone outside engineering and have them repeat them back. Fix whatever came back wrong
  • Attach one measured number to each project: the baseline, the change, and the window it was measured over. Where nothing was ever measured, say that plainly rather than reaching for a plausible percentage
  • Time the background walkthrough against a clock. If it runs past two minutes, compress the earliest role to a single clause and spend the recovered time on the most recent one
PracHub interview research ↗
02

Technical Evaluation

reported

Most of the time lost in this format is not lost to thinking. It goes to a standard-library call you half-remember, an off-by-one in a loop bound, and a debugging loop that mutates code at random until something passes. When output is wrong, stop re-reading the whole function: take the smallest input that reproduces it and walk the state through by hand, printing intermediates if the environment allows. Guessing at a fix without a failing case you understand is how a five-minute bug becomes twenty, and the clock does not pause while you do it.

What to demonstrate

  • Whether you reach the right structure without a detour, and can write it from memory rather than only recall that one exists
  • Whether overflow is considered where the language has fixed-width integers, since a signed 32-bit value stops at 2,147,483,647 and then wraps in Java, is undefined behaviour in C++, and does not arise in Python, whose integers grow instead
  • Whether recursion depth is treated as a constraint on large inputs, given that CPython's default limit is 1000 frames and a deep recursion can exhaust the stack in any language where an iterative version would not
  • Whether a failing case is isolated and explained before any edit is made to the code

How to prepare

  • From an empty file and with no references open, implement the pieces you lean on most: a heap push and pop, an iterative DFS with an explicit stack, and a binary search whose midpoint is written lo + (hi - lo) / 2, which avoids the overflow that (lo + hi) / 2 can hit in a fixed-width integer type
  • Time yourself on the ten library calls you look up most, such as sorting with a custom comparator, splitting and joining strings, and finding the next key at or above a value in an ordered map, until the lookup is gone
  • Take a solution you know is broken and, before touching it, write one sentence naming the input, the expected value and the actual value. Repeat until you do it without deciding to.
PracHub interview research ↗
03

Practical Exercise

reported

You cannot drill a format you do not know, so put the preparation into material that travels. Three pieces of your own work, each rehearsed until you can take a follow-up you did not anticipate, will carry a conversation or a code walkthrough equally well. Specificity is what separates that from filler. A number needs its definition before it means anything: a p99 is over some window and measured at some hop, and a server-side figure excludes the queueing and network time a client would see. The number you cannot qualify is the one to leave out.

What to demonstrate

  • Whether your examples carry detail only someone who did the work would hold, such as what the binding constraint actually was, which alternative you rejected and why it was worse, and what you measured on each side of the change
  • Whether a number survives one follow-up, meaning you can say what it was measured over and whether it moved because of your change or merely alongside it
  • Whether a failure is described with the specific change that followed it, rather than a lesson stated in general terms
  • Whether your part in a team effort is stated accurately, including what other people did

How to prepare

  • Write a page on each of three projects covering the constraint, the option you rejected, the measurement before and after, and what went wrong. Cut any line you cannot take a follow-up on, since you are writing the parts you will be pressed on rather than a summary.
  • Recover the real figures while you still have access: request volume, data size, latency with its percentile and window, team size, timeline. Note where each came from, whether a dashboard, a design document or memory, and mark the estimates so you can say which they are out loud.
  • Take your weakest project story to someone who works in a different area and have them ask why four times in succession. The point where you run out of answer is the part to go and re-read before the round.
PracHub interview research ↗
04

Department Director Discussion

reported

When a round has no standard shape, it is often there because something is still open: an area no earlier conversation reached, a round where the signal came out mixed, or a decision someone is not ready to make alone. Work out which by going back over what each earlier round actually covered rather than how it felt, and arrive able to give evidence on that point without being asked twice. Weak answers replay the loop's earlier material at the same depth. Strong ones go a level deeper and stay consistent with what you already said.

What to demonstrate

  • Whether your account of a project matches the one you gave earlier in the loop, since what you said before may be available to whoever runs this round
  • Whether you can go a level deeper on something already covered, reaching the decision and its alternatives rather than repeating the summary
  • Whether you state your own uncertainty accurately, including parts of a system you did not build and decisions you inherited, instead of claiming even ownership across all of it
  • Whether you can answer a question you handled poorly earlier by naming what you missed, rather than delivering a polished second version as if the first had not happened

How to prepare

  • Reconstruct the loop on one page: for each round, the questions you were asked and the answer you actually gave, not the better one you thought of afterwards. The gaps on that page are your best available guess at why this round exists.
  • Take the two claims you made earlier that carry the most weight and assemble the backing for each: the measurement, the date, what broke, the decision you would make differently now.
  • Write down the three facts about your work that must not drift between tellings, such as team size, timeline and your own role, and check your stories against that list rather than trusting recall under pressure
PracHub interview research ↗
05

Final Decision-Making

reported

A day like this is several different games in a row, and the expensive mistake is carrying the previous one into the next room. Coding rewards narrow precision and finishing inside a timer. Design rewards breadth, stated assumptions and naming what you are deliberately not building. Behavioural rewards specificity about people and decisions. Candidates who over-engineer a coding problem they were supposed to finish, or who start sketching class hierarchies before anyone has agreed what the system has to do, are usually still playing the last round. Between rooms, name out loud which game the next one is.

What to demonstrate

  • Whether the coding round ends with something that runs and has been traced against a degenerate input, rather than an extensible design that was never finished
  • Whether a design discussion opens by agreeing on traffic shape, read-to-write ratio and what is allowed to be stale, instead of proceeding from an architecture you arrived with
  • Whether a behavioural answer names a person, a disagreement and what you did about it, rather than describing the system the story happened inside
  • Whether the opening habits still appear late in the day: restating the problem, asking for constraints, saying the plan before typing

How to prepare

  • Book three mocks of different types back to back on one afternoon and ask each interviewer afterwards which round you answered in the wrong mode
  • Write a three-line opening script per round type — coding: restate, name the approach and its cost, then type; design: ask for scale, read-write mix and what must not break; behavioural: name the person, the stakes and the decision — and run it off a card so the switch is mechanical rather than remembered
  • Practise coding with a timer you do not extend, stopping when it stops, so the trained reflex is to finish a correct solution rather than to keep improving one
PracHub interview research ↗

PracHub editorial advice for the preparation topics above.

01

Treating the manifest as the authorisation boundary.

Checking entitlement when the manifest is requested feels natural, because that is where the session visibly begins. But the manifest is a cacheable document and the segment URLs inside it carry no identity, so anyone who obtains it plays until the delivery token expires, and a subscriber who cancels mid-title finishes the title. Authorisation has to sit at the licence request, the only thing on the path that is per-user and uncacheable by construction.

02

Assuming one encrypted copy of the ladder serves every DRM system.

Common encryption (ISO/IEC 23001-7) defines several protection schemes, and two matter in practice: AES-CTR full-sample ('cenc') and AES-CBC pattern encryption ('cbcs'). One of the three widely deployed DRM systems accepts only cbcs, and older client versions of the other two accept only cenc, so a single-copy strategy is correct only if every device class you still support has reached cbcs. Discovering late that one legacy class has not means a second packaging run, a second set of objects in every cache, and roughly double the storage for the affected catalogue.

03

Answering a debugging question with a guess instead of a bisection

Give a procedure that halves the search space at each step: confirm the symptom reproduces, establish the last known-good version, input or timestamp, then bisect over commits, over the data, or over the layers of the request path. A plausible cause with no way to confirm it is the same move whether it happens to be right or wrong, which is why it scores nothing.

04

Tests that assert on the implementation rather than the behaviour

Assert on what a caller can observe, not on the number of internal calls or the shape of a private field. A test that breaks on every refactor but still passes when the answer is wrong costs more than it protects.

Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.

9 technical prompts3 include a worked solution

Rank delivery groups by rebuffer ratio without ranking on noise

medium
top-kheapaggregation

A completed hour of telemetry yields roughly 10^6 groups keyed (cdn_pop, device_class, isp), each arriving as an unordered stream of per-minute partials carrying qualified_starts and rebuffered_starts. On-call needs the 50 worst groups by rebuffer ratio, excluding groups too small to mean anything: a group with 3 starts and 1 rebuffer reads as 33%. Return the top 50 with their ratios and sample counts. Target something better than a full sort, and state both time and space.

Approach
  1. Two phases, forced by the fact that the ranking key is a ratio that is only final once every partial for a group has landed. Phase one is a hash aggregation of partials into per-group counters, O(n) time and O(g) space for g groups.
  2. Phase two selects with a size-50 min-heap keyed on the ratio: O(g log k) time and O(k) space, against O(g log g) for a sort. At g = 10^6 and k = 50 that is about 6 comparisons per group rather than 20. Quickselect is O(g) but needs every group resident and mutable, so the heap wins when phase one streams.
  3. Apply the minimum-sample floor before the heap, never after. At a floor of 200 qualified starts the standard error of the ratio is sqrt(p(1-p)/n), about 1.5 percentage points at p = 5%, so the ordering carries information. Filtering after the heap leaves it full of three-sample groups and returns fewer than 50 usable rows.
  4. Offer the alternative that removes the arbitrary cutoff: rank on the lower bound of a Wilson score interval, which shrinks small groups toward the population mean automatically. The cost is a heavier comparison per group and a figure that is no longer the raw ratio people expect on the dashboard.
  5. If g does not fit in memory, partition by hash of the group key, take a local top-50 per shard and merge. Top-k decomposes this way only because each group's aggregate is complete within its shard, which the hash partition guarantees.
Follow-up
  • Make it a rolling one-hour top-50 recomputed every minute. What changes when groups must also be evicted as old minutes leave the window?
  • Two groups tie on ratio but differ 100x in volume. Which do you page on, and what does that argue about ranking on count-weighted impact instead of on ratio?

Alert on a rolling rebuffer ratio over a time-based window

mediumWorked solution
sliding windowtwo pointersalerting

A session's QoE samples arrive in playback order as (sequence, wall_clock_ms, wall_delta_ms, rebuffer_ms). Find the earliest sample at which the rebuffer ratio over the trailing 120,000 ms of wall time exceeds 5%, ignoring any window covering under 30,000 ms of wall time. Sample spacing varies between 2 and 30 seconds depending on device and player version, and a long session can carry 10^5 samples. Return the sample index or none. Target O(n) time and O(1) additional space.

Approach
  1. Two indices over the time-ordered array with running integer sums of wall_delta_ms and rebuffer_ms. Advance the right index one sample at a time, then pull the left index forward while the window's wall span exceeds 120,000 ms, subtracting as you go. Each index only moves forward, so total work is O(n) with two accumulators and no auxiliary structure.
  2. Define the window by accumulated wall time, not by sample count. Spacing varies by more than 10x, so a fixed count of samples is a window somewhere between four minutes and an hour depending on which device reported it.
  3. Gate the predicate on a minimum covered span of 30,000 ms. Without it, the first two samples of any session containing one stall produce a window at or near 100% and every session with a startup stall pages someone.
  4. Name the naive alternative and its cost: recomputing the sums across the window at each step is O(n * w), roughly 6 x 10^6 operations at 10^5 samples and a 60-sample window. Acceptable for one session on demand, not acceptable when the same evaluation runs against 10^6 concurrent sessions.
  5. Keep both accumulators as int64 milliseconds so add-then-subtract is exact; a float accumulator drifts over 10^5 add/subtract pairs and the drift is largest on exactly the longest sessions.
Worked solution 20 min
  1. Write the two-pointer loop with both accumulators and the eviction condition on wall span.
  2. Add the minimum-coverage gate and show which sessions it suppresses.
  3. Argue the O(n) bound from the fact that each index advances monotonically.
  4. Trace a session with one 5-second stall followed by 10 minutes of clean playback and confirm the alert clears once the stall leaves the window.
EXPECTED RESULTThe index of the first sample whose trailing 120,000 ms window covers at least 30,000 ms and exceeds a 5% rebuffer ratio, found in a single forward pass with two int64 accumulators and O(1) extra space.
Follow-up
  • Evaluate it incrementally as samples stream in with no array retained. What state do you keep per session, and what is its memory bound at 10^6 concurrent sessions?
  • A late sample arrives out of order after the window has already moved past its timestamp. Do you re-evaluate, and what does that do to the idempotency of the alert?

Recompute the downstream job set after a single rendition re-encode

medium
dagtopological sortinvalidation

The packaging pipeline for one content version is a DAG of up to 10^5 jobs and 5 x 10^5 edges: source validation, per-chunk encodes, per-rendition concatenation, packaging, encryption, manifest generation, publish. QC fails one video rung, so its chunk encodes are re-run on a different encoder build. Given the edge list and a set of dirty job ids, return every job that must re-run plus a valid execution order for them, and report whether the graph contains a cycle. Target O(V + E) time.

Approach
  1. Build forward adjacency (job -> dependents) in one O(E) pass over the edge list. No sorting is required anywhere in this problem.
  2. Collect the affected set S by BFS or DFS from the dirty set over forward edges, marking a visited bitset. O(V + E), each node and edge touched once.
  3. Order S with Kahn's algorithm run on the induced subgraph, recomputing in-degrees counting only edges whose tail is also in S. Reusing whole-graph in-degrees is the failure here: clean predecessors outside S leave phantom in-degrees, the ready queue starts empty and nothing is ever emitted.
  4. Detect the cycle from Kahn's own termination condition: if emitted count < |S|, the residual nodes contain a cycle and everything it feeds. Report the residual set rather than asserting, because a malformed encoder profile is a data bug, not a crash.
  5. State the trade-off against re-running the whole version: the affected set is one rung's chunks plus concatenation, packaging, encryption, manifest and publish, so you save the 6-12x ladder fan-out. But manifest and publish are common descendants of every rung and are therefore always in S, which is precisely why re-encoding one rung is not a local change.
Follow-up
  • The re-encode uses a different encoder build. Which additional nodes become dirty, and why is encoder_build_id pinned per asset rather than taken from the pipeline default?
  • Two rungs fail QC concurrently and two invalidation runs overlap. What makes the recomputation idempotent so the second run does not restart jobs the first already completed?

For someone fluent in a dynamic language who has shipped real work but has never had to say what the runtime is doing underneath. The week is built on measuring and deliberately breaking things, because the questions that expose this background are the ones where the interviewer asks why a second time.

Small steps. Visible outcomes.0 / 7 completed
ONE WEEK · YOUR PACE

Prepare, practise & reflect

One practical outcome each day. Spend longer where you need it.

0 / 7 done
01Measure before reasoning
  • Take a slow piece of your own code, write down in advance where you believe the time goes, then profile it and record how wrong the guess was. The cost is usually an allocation you did not notice or an accidental quadratic membership test.
  • Replace one list membership test inside a loop with a set and measure at a thousand, ten thousand and a hundred thousand elements, confirming the shape of the curve rather than only that it got faster.
  • Write down the three quantities you can now measure instead of assert: wall time, peak memory, and call count for the function you suspected.

Deliverable: A before-and-after profile of real code plus a written note on the size of the gap between the guess and the measurement.

Practice prompt ↗Practice prompt ↗Worked solution ↗
02References, copies, and the bugs they produce
  • Write the function with a mutable default argument, call it three times, and explain the accumulating result: the default is evaluated once when the function is defined, so every call shares one object.
  • Build a nested structure, take a shallow copy, mutate an inner element, and show that both views changed, because a shallow copy duplicates the container and not the elements. Then fix it with a deep copy and state the cost you just accepted.
  • Write two functions, one mutating its argument in place and one rebinding the local name, and predict the caller's view of each before running it. That single distinction produces most of the bugs that pass their tests.

Deliverable: Three small programs whose output you predicted correctly before running, each with a one-line statement of the rule underneath.

Practice prompt ↗Practice prompt ↗
03Types, once, in a language that checks them
  • Port one module you have already written, roughly a hundred lines, into a statically typed language, and record every place the compiler demanded an answer your original had left implicit: a value that can be absent, a numeric width, a case never handled.
  • Write the same signature in both languages and state what the static one guarantees before the program runs and what it does not, since it will not save you from a wrong algorithm or an index out of range.
  • Write the difference between an interface satisfied by declaration and one satisfied structurally, with one case each where the other approach would miss the mistake.

Deliverable: One module in two languages plus a list of the questions the type checker forced you to answer.

Practice prompt ↗Practice prompt ↗
04Concurrency, starting with what actually runs at the same time
  • Run the same CPU-bound function across four threads and four processes and measure both. Under the default CPython build the threaded version will not speed up, because only one thread executes bytecode at a time; the process version will. Check which build you are on first, since free-threaded builds remove that lock and change the result.
  • Then run a blocking I/O workload across four threads and measure it speeding up, because the interpreter releases that lock around blocking calls, which is why treating threads as useless is wrong as a general claim.
  • Build the lost update: two threads each incrementing a shared counter a hundred thousand times, and show a final value below the expected sum, because an increment is a load, an add and a store and the thread can be suspended between them. Fix it with a lock and then measure what the lock costs.

Deliverable: Three measurements, threads against processes on CPU work, threads on I/O work, and a demonstrated lost update, each with the mechanism written underneath.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05Debugging as a procedure rather than an instinct
  • Work one real failure as a bisection: find a revision or an input size where it is good and one where it is bad, halve repeatedly, and state the two assumptions bisection needs, that the property changes exactly once across the range and that the test is reliable.
  • Minimise one failing input to the smallest version that still fails, and record how many rounds it took.
  • Keep a hypothesis log for one bug in three columns, what I believe, what would disprove it, what I observed, and stop yourself the first time you are about to change two things at once.

Deliverable: One bug worked to root cause with a written hypothesis log and a minimised reproducing input.

Practice prompt ↗Practice prompt ↗
06Tests that catch the bug you are about to write
  • Implement an LRU cache with a capacity bound, then write the three test cases that would catch an off-by-one in eviction: insert exactly capacity items and assert nothing was evicted, insert one more and assert the least recently used key is the one gone, and read an old key just before that insert so the eviction victim changes.
  • Add a property test comparing your implementation against a deliberately slow reference, an ordered list scanned linearly, over a few thousand random operation sequences, because a slow reference finds the cases you would not have thought to write.
  • Write one numeric test that fails under exact equality and passes with a tolerance, and state why the tolerance has to be relative rather than absolute once the magnitudes grow.

Deliverable: An LRU implementation with three boundary tests, one property test against a slow reference, and one tolerance-based numeric test.

Practice prompt ↗Practice prompt ↗
07Debug something broken, out loud
  • Have someone plant three defects in a two-hundred-line program, an off-by-one, a shared mutable state bug, and a wrong error-handling path, then find them while narrating, under a fixed rule: state the hypothesis before touching anything.
  • Time each one and record which tool found it, reading, a printed value, a debugger, or a test, because the question asked in interviews is how you would find it rather than what it was.
  • Write the sentence you will use when you do not yet know the cause, one that names the next measurement instead of offering a guess.

Deliverable: A recorded debugging session with time-to-find per defect and the method that found each.

Practice prompt ↗Worked solution ↗

Expand any day for tasks and deliverables. Your progress is saved on this device.

When the requirements were thin, the interesting part is how you fenced the problem off: the assumption you wrote down, who you got to confirm it, the narrow version you shipped first so the rest stayed cheap to change. Guessing and being right is luck. Guessing in writing, where someone could correct you, is method.

How do you handle feedback or constructive criticism on your technical…

medium
behavioural and engineering judgement

How do you handle feedback or constructive criticism on your technical work?

Approach
  1. State the situation in two sentences and spend the rest on the reasoning.
  2. Close with what you would do differently, concretely.
  3. Pick a story where you made the decision, not one where you watched it.
Follow-up
  • What would you do differently if you ran that again?
  • How did you know your change caused the improvement?

Where do you see yourself in your career in a few years?

medium
behavioural and engineering judgement

Where do you see yourself in your career in a few years?

Approach
  1. Name the disagreement and how you resolved it with evidence.
  2. Give the blast radius: what could have broken, and what you measured.
  3. Close with what you would do differently, concretely.
Follow-up
  • What would you do differently if you ran that again?
  • How did you know your change caused the improvement?

What motivates you to work in a collaborative, team-based environment?

medium
behavioural and engineering judgement

What motivates you to work in a collaborative, team-based environment?

Approach
  1. State the situation in two sentences and spend the rest on the reasoning.
  2. Pick a story where you made the decision, not one where you watched it.
  3. Give the blast radius: what could have broken, and what you measured.
Follow-up
  • What would you do differently if you ran that again?
  • How did you know your change caused the improvement?

Can you describe your experience with specific software programs and d…

medium
behavioural and engineering judgement

Can you describe your experience with specific software programs and development environments?

Approach
  1. Name the disagreement and how you resolved it with evidence.
  2. State the situation in two sentences and spend the rest on the reasoning.
  3. Close with what you would do differently, concretely.
Follow-up
  • How did you know your change caused the improvement?
  • What did you decide not to do, and why?
  • 01

    How do you handle feedback or constructive criticism on your technical work?

  • 02

    Where do you see yourself in your career in a few years?

  • 03

    What motivates you to work in a collaborative, team-based environment?

  • 04

    Can you describe your experience with specific software programs and development environments?

PracHub interview preparation framework ↗
Is this an official Advice Media interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at Advice Media. Rounds and questions reflect what candidates have reported, not a process Advice Media has published, and they change over time. Confirm the current format and scope with your recruiter.

PracHub interview research ↗
How long does the interview process typically take?

The timeline can vary based on the specific role and team, but it is generally a swift and professional process. Candidates report clear communication that keeps them informed at every step.

PracHub interview research ↗
What is the best way to prepare for the technical portion?

Focus on your past projects. Be prepared to explain the technical challenges you faced, the decisions you made, and the final outcomes.

PracHub interview research ↗
Is the work environment collaborative?

Yes, collaboration is central to the company's culture. You will work closely with designers, project managers, and other engineers to deliver high-quality solutions.

PracHub interview research ↗
Sources & methodology 3 sources ↗

No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.