ЁЯПл The SchoolтА║ЁЯЦея╕П EC2тА║ЁЯТ│ рдзрдбрд╛ 08 тАФ Pricing: рддрд╛рд╕рд╛рдиреЗ рдкреИрд╕реЗ рднрд░рд╛, рд╡рд░реНрд╖рд╛рдЪреЗ рд╡рдЪрди рджреНрдпрд╛, рдХрд┐рдВрд╡рд╛ рд░рд┐рдХрд╛рдореА рдЬрд╛рдЧрд╛ рдШреНрдпрд╛
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯТ│ рдзрдбрд╛ 08 тАФ Pricing: рддрд╛рд╕рд╛рдиреЗ рдкреИрд╕реЗ рднрд░рд╛, рд╡рд░реНрд╖рд╛рдЪреЗ рд╡рдЪрди рджреНрдпрд╛, рдХрд┐рдВрд╡рд╛ рд░рд┐рдХрд╛рдореА рдЬрд╛рдЧрд╛ рдШреНрдпрд╛

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 ┬╖ рдорд╛рдЧреАрд▓: lesson-07-metadata-roles ┬╖ рдкреБрдвреАрд▓: lesson-09-auto-scaling


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ07, рдЖрдгрд┐ рддреНрдпрд╛рдЪ рдбреЗрд╕реНрдХрд╕рд╛рдареА рдкреИрд╕реЗ рднрд░рдгреНрдпрд╛рдЪреЗ рддреАрди рдорд╛рд░реНрдЧ тАФ on-demand, Savings Plans рдЖрдгрд┐ spot тАФ рд▓реЛрдХ рд╡рд┐рд╕рд░рддрд╛рдд рддреЗ рдЦрд░реНрдЪ (stopped рдбреЗрд╕реНрдХрд╡рд░рдЪреЗ disks, public IPv4 addresses, data transfer), рдЖрдгрд┐ рдПрдХ calculator, ec2/costs.py рдордзреАрд▓ monthly(). рд╕рд░реНрд╡ рдХрд┐рдорддреА us-east-1 Linux рдЪреНрдпрд╛ рдЕрдВрджрд╛рдЬреЗ рдЖрдХрдбреНрдпрд╛ рдЖрд╣реЗрдд: рдкреИрд╢рд╛рдЪреНрдпрд╛ рдмрд╛рдмрддреАрдд рдПрдЦрд╛рджреНрдпрд╛ рдЖрдХрдбреНрдпрд╛рд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреНрдпрд╛рдкреВрд░реНрд╡реА EC2 pricing page рддрдкрд╛рд╕рд╛. рдЦрд░рд╛ рдзрдбрд╛ рдЧреБрдгреЛрддреНрддрд░рд╛рдВрдордзреНрдпреЗ рдЖрд╣реЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдЕрднреНрдпрд╛рд╕рд┐рдХрд╛ рдЪрд╛рд▓рд╡рдгрд╛рд░реА рдХрдВрдкрдиреА рдПрдХрд╛рдЪ рдбреЗрд╕реНрдХрд╕рд╛рдареА рддреАрди рдкрд░реНрдпрд╛рдп рджреЗрддреЗ.

  1. рдмрд╕рд╛рд▓ рддрд┐рддрдХреЗ рдкреИрд╕реЗ ЁЯТ╡ (on-demand): рдЖрдд рдпрд╛, рдмрд╕рд╛, рд╕реЗрдХрдВрджрд╛рдиреБрд╕рд╛рд░ рдкреИрд╕реЗ рднрд░рд╛, рд╣рд╡реЗ рддреЗрд╡реНрд╣рд╛ рдирд┐рдШрд╛. рддрд╛рд╕рд╛рд▓рд╛ рд╕рд░реНрд╡рд╛рдд рдорд╣рд╛рдЧ, рдкрдг рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рд╕реНрд╡рд╛рддрдВрддреНрд░реНрдп.
  2. рд╡рд░реНрд╖рд╛рдЪреЗ рд╡рдЪрди ЁЯУЭ (Savings Plans): "рдореА рдПрдХ рдХрд┐рдВрд╡рд╛ рддреАрди рд╡рд░реНрд╖реЗ, рджрд░ рддрд╛рд╕рд╛рд▓рд╛, рд╕рд╛рдзрд╛рд░рдг рдЗрддрдХреЗ рдкреИрд╕реЗ рдЦрд░реНрдЪ рдХрд░реЗрди рдЕрд╕реЗ рд╡рдЪрди рджреЗрддреЛ." рддреНрдпрд╛рдмрджрд▓реНрдпрд╛рдд рдореЛрдареА рд╕реВрдЯ тАФ рдкрдг рддреБрдореНрд╣реА рди рдЖрд▓реЗрд▓реНрдпрд╛ рджрд┐рд╡рд╢реАрд╣реА рд╡рдЪрдирд╛рдЪреЗ рдкреИрд╕реЗ рднрд░рд╛рд╡реЗ рд▓рд╛рдЧрддрд╛рдд.
  3. рд░рд┐рдХрд╛рдореА рдЬрд╛рдЧрд╛ рдШреНрдпрд╛ ЁЯкС (spot): рдЖрддреНрддрд╛ рдХреЛрдгреАрд╣реА book рди рдХреЗрд▓реЗрд▓реЗ рдбреЗрд╕реНрдХ, рдореЛрдареНрдпрд╛ рд╕рд╡рд▓рддреАрдд. рдЕрдЯ рдЕрд╢реА: рдкреИрд╕реЗ рднрд░рдгрд╛рд▒реНрдпрд╛ рдЧреНрд░рд╛рд╣рдХрд╛рд▓рд╛ рддреЛ рд╣рд╡рд╛ рдЕрд╕реЗрд▓ рддрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рджреЛрди рдорд┐рдирд┐рдЯрд╛рдВрдЪреА рд╕реВрдЪрдирд╛ рдорд┐рд│рддреЗ рдЖрдгрд┐ рдЙрдард╛рд╡реЗ рд▓рд╛рдЧрддреЗ.

рд╣реБрд╢рд╛рд░ рд╢рд╛рд│рд╛ рддрд┐рдиреНрд╣реА рд╡рд╛рдкрд░рддреЗ: рдиреЗрд╣рдореА рднрд░рд▓реЗрд▓реНрдпрд╛ рдбреЗрд╕реНрдХрд╕рд╛рдареА рд╡рдЪрди, рдЧрд░реНрджреАрд╕рд╛рдареА рдмрд╕рд╛рд▓-рддрд┐рддрдХреЗ-рдкреИрд╕реЗ, рдЖрдгрд┐ рдордзреНрдпреЗрдЪ рдерд╛рдВрдмрд╡реВрди рдкреБрдиреНрд╣рд╛ рд╕реБрд░реВ рдХрд░рддрд╛ рдпреЗрдгрд╛рд▒реНрдпрд╛ рдЧреГрд╣рдкрд╛рдард╛рд╕рд╛рдареА рд░рд┐рдХрд╛рдореНрдпрд╛ рдЬрд╛рдЧрд╛.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    desk["ЁЯЦея╕П one m7g.large, one month<br/>approximate us-east-1 prices"]
    od["ЁЯТ╡ on-demand ┬╖ $59.57"]
    sp1["ЁЯУЭ 1-yr Compute Savings Plan ┬╖ $42.89"]
    sp3["ЁЯУЭ 3-yr Compute Savings Plan ┬╖ $29.78"]
    spot["ЁЯкС spot (typical) ┬╖ $17.87<br/>2-minute notice"]
    desk --> od
    desk --> sp1
    desk --> sp3
    desk --> spot
    disk["ЁЯТ╛ + 20 GB gp3 ┬╖ $1.60 тАФ billed even while stopped"]
    od -.-> disk
    use["steady base тЖТ Savings Plan ┬╖ spikes тЖТ on-demand ┬╖ batch, CI, stateless тЖТ spot"]
    spot -.-> use

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l08

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдХрд╛рд╣реА рдорд┐рдирд┐рдЯрд╛рдВрдд рдШреЗрддрд▓реЗрд▓реНрдпрд╛ рдирд┐рд░реНрдгрдпрд╛рдВрд╡рд░ рддреЛрдЪ fleet рджреБрдкреНрдкрдЯ рдХрд┐рдВрд╡рд╛ рдирд┐рдореНрдореНрдпрд╛ рдЦрд░реНрдЪрд╛рдЪрд╛ рд╣реЛрдК рд╢рдХрддреЛ: рдХреЛрдгрддрд╛ purchase option, рдХреЛрдгрддрд╛ processor, рддреЛ рд░рд╛рддреНрд░реА рдЪрд╛рд▓рддреЛ рдХреА рдирд╛рд╣реА. рдЖрдгрд┐ рдХрд╛рд░рдг рдмрд┐рд▓ рдорд╣рд┐рдиреНрдпрд╛рдирдВрддрд░ рдпреЗрддреЗ тАФ рддреЛрдкрд░реНрдпрдВрдд рддреЛ рдирд┐рд░реНрдгрдп рдирд╕реВрди рдЗрддрд┐рд╣рд╛рд╕ рдЭрд╛рд▓реЗрд▓рд╛ рдЕрд╕рддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

ec2/costs.py рдордзреНрдпреЗ рдЖрда types рдЪреНрдпрд╛ рдЕрдВрджрд╛рдЬреЗ on-demand рдХрд┐рдорддреА, gp3 рдЖрдгрд┐ snapshot рдХрд┐рдорддреА, рдЖрдгрд┐ plans рдЪреЗ рдвреЛрдмрд│ рдЧреБрдгрдХ рдЖрд╣реЗрдд (1-yr Compute Savings Plan 0.72, 3-yr 0.50, spot (typical) 0.30). monthly(itype, plan, hours, count, gp3_gb) (compute $, storage $) рдкрд░рдд рдХрд░рддреЗ, рдЖрдгрд┐ storage рдЪреЗ рдмрд┐рд▓ рддрд╛рд╕ рдХрд┐рддреАрд╣реА рдЕрд╕рд▓реЗ рддрд░реА рд▓рд╛рдЧрддреЗ. ec2/demo.py рдордзреАрд▓ pricing() рдПрдХрд╛ m7g.large рдЪреА рдПрдХрд╛ рдорд╣рд┐рдиреНрдпрд╛рдЪреА рдХрд┐рдВрдордд рдЪрд╛рд░ рдкреНрд░рдХрд╛рд░реЗ рдХрд╛рдврддреЗ, рдордЧ рдлрдХреНрдд office hours, рдордЧ Graviton рд╡рд┐рд░реБрджреНрдз Intel.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 ec2/demo.py pricing
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2"); import costs
# three web desks all month: Intel vs Graviton, on-demand vs a 1-year Savings Plan
for itype in ("m7i.large", "m7g.large"):
    for plan in ("on-demand", "1-yr Compute Savings Plan"):
        c, s = costs.monthly(itype, plan, count=3, gp3_gb=20)
        print(f"3 ├Ч {itype:<10} {plan:<26} ${c + s:>7.2f}/month")
i, g = costs.PRICE_PER_HOUR["m7i.large"][2], costs.PRICE_PER_HOUR["m7g.large"][2]
print(f"Graviton saves about {(1 - g / i) * 100:.0f}% per hour at the same size")
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS credentials рд▓рд╛рдЧрддрд╛рдд; рдлрдХреНрдд рд╡рд╛рдЪрди; Price List API us-east-1 рдордзреВрди рджрд┐рд▓рд╛ рдЬрд╛рддреЛ):

aws pricing get-products --region us-east-1 --service-code AmazonEC2 \
    --filters Type=TERM_MATCH,Field=instanceType,Value=m7g.large \
              Type=TERM_MATCH,Field=regionCode,Value=us-east-1 \
              Type=TERM_MATCH,Field=operatingSystem,Value=Linux \
              Type=TERM_MATCH,Field=tenancy,Value=Shared \
              Type=TERM_MATCH,Field=preInstalledSw,Value=NA \
              Type=TERM_MATCH,Field=capacitystatus,Value=Used \
    --max-items 1
aws ec2 describe-spot-price-history --instance-types m7g.large \
    --product-descriptions "Linux/UNIX" --max-items 5 --region us-east-1

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

pricing рдЫрд╛рдкрддреЗ on-demand compute $ 59.57 + 20 GB gp3 $1.6, 1-yr Compute Savings Plan compute $ 42.89, 3-yr Compute Savings Plan compute $ 29.78, spot (typical) compute $ 17.87, рдордЧ office hours only (8 h ├Ч 22 days) on-demand: compute $14.36 + disk $1.6 тАФ a stopped desk still pays for its disk рдЖрдгрд┐ Graviton vs Intel, same size: m7g $0.0816/h vs m7i $0.1008/h. рддреБрдордЪрд╛ snippet рдЫрд╛рдкрддреЛ 3 ├Ч m7i.large on-demand тАж $ 225.55/month, тАж 1-yr тАж $ 163.74, 3 ├Ч m7g.large on-demand тАж $ 183.50, тАж 1-yr тАж $ 133.47, рдЖрдгрд┐ Graviton saves about 19% per hour at the same size тАФ Graviton рдЖрдгрд┐ Savings Plan рдорд┐рд│реВрди рдмрд┐рд▓ рд╕реБрдорд╛рд░реЗ 40% рдиреЗ рдХрдореА рд╣реЛрддреЗ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рдПрдХрд╛рдЪ рдбреЗрд╕реНрдХрдЪреНрдпрд╛ рдЕрдиреЗрдХ рдХрд┐рдорддреА рдЕрд╕рддрд╛рдд, рддреНрдпрд╛ рддреБрдореНрд╣реА рдореЛрдЬреВ рд╢рдХрддрд╛, рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдд рдореЛрдареА рдмрдЪрдд рдЙрдкрд╛рдп рдПрдХрдореЗрдХрд╛рдВрд╡рд░ рд░рдЪрд▓реНрдпрд╛рдиреЗ рд╣реЛрддреЗ тАФ рдпреЛрдЧреНрдп processor, рдпреЛрдЧреНрдп рддрд╛рд╕, рдЖрдгрд┐ рдордЧ рдпреЛрдЧреНрдп рд╡рдЪрди.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдЕрдиреБрднрд╡реА teams рджрд░ рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛ рдЦрд░реНрдЪрд╛рдЪрд╛ рдЖрдврд╛рд╡рд╛ рдШреЗрддрд╛рдд: right-sizing рд╕рд╛рдареА Compute Optimizer, рд╕реНрдерд┐рд░ baseline рднреЛрд╡рддреА Savings Plans coverage, CI runners рдЖрдгрд┐ batch workers рд╕рд╛рдареА spot, invoice рдпреЗрдгреНрдпрд╛рдЖрдзреАрдЪ alert рджреЗрдгрд╛рд░реЗ budgets, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЦрд░реНрдЪрд╛рд▓рд╛ рдХреЛрдгрд╛рдЪрд╛ рддрд░реА рдХрд░рдгрд╛рд░реЗ tags.

тПня╕П рдкреБрдвреЗ

рд╕рд░реНрд╡рд╛рдд рд╕реНрд╡рд╕реНрдд рдбреЗрд╕реНрдХ рдореНрд╣рдгрдЬреЗ рдЬреЛ рдлрдХреНрдд рдЧрд░рдЬ рдЕрд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛рдЪ рдЕрд╕рддреЛ. Auto Scaling: рджрд┐рд╡рд╕рднрд░ рдбреЗрд╕реНрдХрдЪреА рдпреЛрдЧреНрдп рд╕рдВрдЦреНрдпрд╛.

git checkout lesson-09-auto-scaling

ЁЯТ│ Lesson 08 тАФ Pricing: pay by the hour, promise a year, or take a spare seat

ЁЯУН You are here: Lesson 08 of 12 ┬╖ Previous: lesson-07-metadata-roles ┬╖ Next: lesson-09-auto-scaling


ЁЯУж What's in this branch

Lessons 01тАУ07, plus the three ways to pay for the same desk тАФ on-demand, Savings Plans and spot тАФ the costs people forget (disks on stopped desks, public IPv4 addresses, data transfer), and a calculator, monthly() in ec2/costs.py. All prices are approximate us-east-1 Linux figures: check the EC2 pricing page before you trust a number with money. The ratios are the lesson.

ЁЯзТ Explain like I'm 5

The study-hall company offers three deals for the same desk.

  1. Pay as you sit ЁЯТ╡ (on-demand): walk in, sit, pay by the second, leave whenever you like. The most expensive per hour, the most freedom.
  2. Promise a year ЁЯУЭ (Savings Plans): "I promise to spend about this much per hour, every hour, for one or three years." In return, a big discount тАФ but you pay the promise even on days you do not come.
  3. Take a spare seat ЁЯкС (spot): desks nobody has booked right now, at a deep discount. The catch: if a paying customer needs it, you get a two-minute warning and must stand up.

A smart school uses all three: a promise for the desks that are always busy, pay-as-you-sit for the rush, and spare seats for homework that can be paused and picked up again.

ЁЯЧ║я╕П Diagram

flowchart LR
    desk["ЁЯЦея╕П one m7g.large, one month<br/>approximate us-east-1 prices"]
    od["ЁЯТ╡ on-demand ┬╖ $59.57"]
    sp1["ЁЯУЭ 1-yr Compute Savings Plan ┬╖ $42.89"]
    sp3["ЁЯУЭ 3-yr Compute Savings Plan ┬╖ $29.78"]
    spot["ЁЯкС spot (typical) ┬╖ $17.87<br/>2-minute notice"]
    desk --> od
    desk --> sp1
    desk --> sp3
    desk --> spot
    disk["ЁЯТ╛ + 20 GB gp3 ┬╖ $1.60 тАФ billed even while stopped"]
    od -.-> disk
    use["steady base тЖТ Savings Plan ┬╖ spikes тЖТ on-demand ┬╖ batch, CI, stateless тЖТ spot"]
    spot -.-> use

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l08

тЭУ What

ЁЯдФ Why

Because the same fleet can cost twice as much, or half as much, depending on decisions that take minutes: which purchase option, which processor, whether it runs at night. And because the bill arrives a month later тАФ by then it is history, not a decision.

ЁЯФз How (in this repo)

ec2/costs.py holds approximate on-demand prices for eight types, gp3 and snapshot prices, and rough plan multipliers (1-yr Compute Savings Plan 0.72, 3-yr 0.50, spot (typical) 0.30). monthly(itype, plan, hours, count, gp3_gb) returns (compute $, storage $), with storage billed whatever the hours. pricing() in ec2/demo.py prices one m7g.large for a month four ways, then office hours only, then Graviton vs Intel.

ЁЯзк Try it

python3 ec2/demo.py pricing
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2"); import costs
# three web desks all month: Intel vs Graviton, on-demand vs a 1-year Savings Plan
for itype in ("m7i.large", "m7g.large"):
    for plan in ("on-demand", "1-yr Compute Savings Plan"):
        c, s = costs.monthly(itype, plan, count=3, gp3_gb=20)
        print(f"3 ├Ч {itype:<10} {plan:<26} ${c + s:>7.2f}/month")
i, g = costs.PRICE_PER_HOUR["m7i.large"][2], costs.PRICE_PER_HOUR["m7g.large"][2]
print(f"Graviton saves about {(1 - g / i) * 100:.0f}% per hour at the same size")
EOF

On a real account (needs AWS credentials; read-only; the Price List API is served from us-east-1):

aws pricing get-products --region us-east-1 --service-code AmazonEC2 \
    --filters Type=TERM_MATCH,Field=instanceType,Value=m7g.large \
              Type=TERM_MATCH,Field=regionCode,Value=us-east-1 \
              Type=TERM_MATCH,Field=operatingSystem,Value=Linux \
              Type=TERM_MATCH,Field=tenancy,Value=Shared \
              Type=TERM_MATCH,Field=preInstalledSw,Value=NA \
              Type=TERM_MATCH,Field=capacitystatus,Value=Used \
    --max-items 1
aws ec2 describe-spot-price-history --instance-types m7g.large \
    --product-descriptions "Linux/UNIX" --max-items 5 --region us-east-1

тЬЕ Verify тАФ what you should see

pricing prints on-demand compute $ 59.57 + 20 GB gp3 $1.6, 1-yr Compute Savings Plan compute $ 42.89, 3-yr Compute Savings Plan compute $ 29.78, spot (typical) compute $ 17.87, then office hours only (8 h ├Ч 22 days) on-demand: compute $14.36 + disk $1.6 тАФ a stopped desk still pays for its disk and Graviton vs Intel, same size: m7g $0.0816/h vs m7i $0.1008/h. Your snippet prints 3 ├Ч m7i.large on-demand тАж $ 225.55/month, тАж 1-yr тАж $ 163.74, 3 ├Ч m7g.large on-demand тАж $ 183.50, тАж 1-yr тАж $ 133.47, and Graviton saves about 19% per hour at the same size тАФ Graviton plus a Savings Plan cuts the bill by about 40%.

ЁЯПБ What you just proved

The same desk has a range of prices, you can compute them, and the biggest savings come from stacking levers тАФ the right processor, the right hours, then the right promise.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: mature teams run a monthly cost review: Compute Optimizer for right-sizing, Savings Plans coverage around the steady baseline, spot for CI runners and batch workers, budgets that alert before the invoice, and tags that make every cost somebody's.

тПня╕П Next

The cheapest desk is the one that is only there when it is needed. Auto Scaling: the right number of desks, all day.

git checkout lesson-09-auto-scaling
тЖР Previousmetadata rolesNext тЖТauto scaling

This page is the lesson's README from the lesson-08-pricing branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.