From 082f773736dc185ea5e3770fa7da92d44da06ea9 Mon Sep 17 00:00:00 2001 From: PatrikBak Date: Thu, 14 May 2026 02:47:54 +0200 Subject: [PATCH] Make handout figure PDFs reproducible asy's bundled Ghostscript stamps /CreationDate, /ModDate, /ID, and the embedded XMP metadata with wall-clock values, producing a spurious diff on every re-render. The Windows GS builds available here ignore SOURCE_DATE_EPOCH and the -dOmit* flags, so the export script now patches those fields in place using values derived from the .asy mtime and a SHA-256 of its contents - same source, same PDF. Co-Authored-By: Claude Opus 4.7 --- data/handouts/Images/_Export-Asy.ps1 | 40 +++++++++++++++++- data/handouts/Images/ag-proof.pdf | Bin 4854 -> 4854 bytes data/handouts/Images/angles-90-60-30.pdf | Bin 7036 -> 7036 bytes .../Images/angles-Ssa-proof-isosceles.pdf | Bin 5466 -> 5466 bytes .../Images/angles-Ssa-proof-one-solution.pdf | Bin 5425 -> 5425 bytes .../Images/angles-Ssa-proof-two-solutions.pdf | Bin 6840 -> 6840 bytes data/handouts/Images/angles-alternate.pdf | Bin 2736 -> 2736 bytes data/handouts/Images/angles-asa-proof.pdf | Bin 6595 -> 6595 bytes .../angles-complementary-in-triangle.pdf | Bin 6280 -> 6280 bytes ...angles-complementary-parallel-solution.pdf | Bin 5343 -> 5343 bytes ...ngles-complementary-parallel-statement.pdf | Bin 4400 -> 4400 bytes ...ing-alternate-supplementary-connection.pdf | Bin 4691 -> 4691 bytes data/handouts/Images/angles-corresponding.pdf | Bin 2737 -> 2737 bytes data/handouts/Images/angles-equilateral.pdf | Bin 6996 -> 6996 bytes .../angles-isosceles-right-triangle.pdf | Bin 5050 -> 5050 bytes .../Images/angles-isosceles-triangle.pdf | Bin 4735 -> 4735 bytes data/handouts/Images/angles-polygon-fan.pdf | Bin 6708 -> 6708 bytes .../Images/angles-polygon-interior.pdf | Bin 7255 -> 7255 bytes data/handouts/Images/angles-polygon.pdf | Bin 6544 -> 6544 bytes data/handouts/Images/angles-sas-proof.pdf | Bin 6313 -> 6313 bytes data/handouts/Images/angles-sas-warning.pdf | Bin 6026 -> 6026 bytes data/handouts/Images/angles-sss-proof.pdf | Bin 6449 -> 6449 bytes .../angles-supplementary-derive-vertical.pdf | Bin 5424 -> 5424 bytes data/handouts/Images/angles-supplementary.pdf | Bin 2681 -> 2681 bytes data/handouts/Images/angles-triangle.pdf | Bin 5581 -> 5581 bytes .../angles-vertical-derive-supplementary.pdf | Bin 4958 -> 4958 bytes data/handouts/Images/angles-vertical.pdf | Bin 2727 -> 2727 bytes data/handouts/Images/box.pdf | Bin 3401 -> 3401 bytes 28 files changed, 38 insertions(+), 2 deletions(-) diff --git a/data/handouts/Images/_Export-Asy.ps1 b/data/handouts/Images/_Export-Asy.ps1 index 7233713e..b8392df6 100644 --- a/data/handouts/Images/_Export-Asy.ps1 +++ b/data/handouts/Images/_Export-Asy.ps1 @@ -5,7 +5,10 @@ # Per .asy file the pipeline is: # 1. Run asy with -noView to render the .asy to a PDF next to the source. asy is run with # -cd so `import _common;` and other relative imports resolve next to the source file. -# 2. Convert the PDF to SVG via Inkscape (matches the conversion path used by _Export-Ggb.ps1 +# 2. Patch the PDF's non-deterministic metadata (timestamps and IDs that the bundled Ghostscript +# stamps with wall-clock values) so re-rendering an unchanged .asy produces a byte-identical +# PDF and stops creating spurious git diffs. +# 3. Convert the PDF to SVG via Inkscape (matches the conversion path used by _Export-Ggb.ps1 # so handout figures coming from either source render identically downstream). param( # One or more directories, .asy files, or PowerShell wildcards (e.g. 'angles-*.asy'). Default @@ -62,7 +65,40 @@ function Convert-OneAsy { throw "asy failed (exit $($proc.ExitCode))" } - # 2. Convert the PDF to plain SVG via Inkscape. The .com launcher on PATH is the console + # 2. Replace the non-deterministic metadata that asy's bundled Ghostscript stamps with wall-clock + # values (/CreationDate, /ModDate, /ID in the trailer plus a second copy of the dates and a + # DocumentID UUID inside the XMP stream). With those derived from the .asy source instead, + # re-rendering an unchanged .asy yields a byte-identical PDF and stops producing spurious git + # diffs. The Windows builds of GS we have access to (asy's bundled 10.x and MiKTeX's 9.25) + # ignore SOURCE_DATE_EPOCH and the -dOmit* flags, so we patch the bytes ourselves. + $mtimeUtc = (Get-Item -LiteralPath $AsyPath).LastWriteTimeUtc + # Date timestamps for the two formats Ghostscript emits: PDF date string in the trailer /Info, + # ISO 8601 in the XMP stream. UTC normalised so the field length doesn't depend on local TZ. + $pdfDate = "D:{0:yyyyMMddHHmmss}+00'00'" -f $mtimeUtc + $xmpDate = "{0:yyyy-MM-ddTHH:mm:ss}+00:00" -f $mtimeUtc + # Identifiers: SHA-256 of the .asy content gives 64 hex chars. First 32 supply the /ID halves + # (PDF spec calls for 16-byte values); next 32 fill the DocumentID UUID positions. + $hash = (Get-FileHash -LiteralPath $AsyPath -Algorithm SHA256).Hash + $idHex = $hash.Substring(0, 32) + $uuidHex = $hash.Substring(32, 32) + $uuid = '{0}-{1}-{2}-{3}-{4}' -f $uuidHex.Substring(0, 8), $uuidHex.Substring(8, 4), $uuidHex.Substring(12, 4), $uuidHex.Substring(16, 4), $uuidHex.Substring(20, 12) + # Read the PDF as Latin1 so each byte round-trips losslessly through a string (PDFs are mostly + # ASCII outside of stream contents, and our regexes never match inside binary streams). + $pdfBytes = [System.IO.File]::ReadAllBytes($finalPdf) + $pdfText = [System.Text.Encoding]::Latin1.GetString($pdfBytes) + # Trailer /Info dict. + $pdfText = [regex]::Replace($pdfText, "/CreationDate\(D:\d{14}[+\-]\d{2}'\d{2}'\)", "/CreationDate($pdfDate)") + $pdfText = [regex]::Replace($pdfText, "/ModDate\(D:\d{14}[+\-]\d{2}'\d{2}'\)", "/ModDate($pdfDate)") + $pdfText = [regex]::Replace($pdfText, "/ID \[<[0-9A-Fa-f]{32}><[0-9A-Fa-f]{32}>\]", "/ID [<$idHex><$idHex>]") + # XMP metadata stream (uncompressed in asy's output). + $pdfText = [regex]::Replace($pdfText, "[^<]+", "$xmpDate") + $pdfText = [regex]::Replace($pdfText, "[^<]+", "$xmpDate") + $pdfText = [regex]::Replace($pdfText, "xapMM:DocumentID='uuid:[0-9a-fA-F-]+'", "xapMM:DocumentID='uuid:$uuid'") + # Every replacement above is the same length as the value it replaced, so the PDF's xref byte + # offsets stay valid without rebuilding the table. + [System.IO.File]::WriteAllBytes($finalPdf, [System.Text.Encoding]::Latin1.GetBytes($pdfText)) + + # 3. Convert the PDF to plain SVG via Inkscape. The .com launcher on PATH is the console # launcher that waits for inkscape.exe, so -Wait is enough. if (Test-Path -LiteralPath $finalSvg) { Remove-Item -LiteralPath $finalSvg -Force } $proc = Start-Process -FilePath $inkscape -ArgumentList @($finalPdf, '--pdf-poppler', '--export-type=svg', '--export-plain-svg', "--export-filename=$finalSvg") -Wait -PassThru diff --git a/data/handouts/Images/ag-proof.pdf b/data/handouts/Images/ag-proof.pdf index ee3ffd8abe883a6ddf7716e73eb94c7edc8c97cc..fb200fe8381d94fd296dd893192ada4c4b56558e 100644 GIT binary patch delta 211 zcmeyS`b~9%H!rV6h>@|CiKUgHnYMw!ocP29{ZOwC+P9L?1AC(H7wZ9d0$m{G^V$k@aZY@oV8y4ot(^EoebSv%^Xb}Ee)Iv+$;<&&5VtVEY0m~ L2&kBROGpL)G3hjv delta 211 zcmeyS`b~9%H!rVch=HM%iKUg1k+y-+wCm4S(sfw{JU!Q>oKLuBr9(f4X*hK6Q_78WkLM&>SNx{l@sCc0*p z#;&?fMh31%t_Ft2W@cvU`jZXC)HXj7JHx02Q~)+h-M~OylS|(>KgA`nBvr%3%E-XT z%)r#p*bt^-^9>1iCMQ=5V{=1869X3)16MZ_M@v%+3sZAvS7S3L17lNDCpSAALMkRF HN=pL(>#;Ie delta 204 zcmexk_Qz~Pk|>v{m63^+v4ysQ(c~OaLuBr9(f4YW=BB3RhDJuZriMm|x`u{nhPnno zpqp%zl4y{el4fj_YNoC~*-%Vv^CPh{j9R8fCSbGF4Gh#Zx%7SWQ(O{DQZ-zxj0}v- z3``A;4Ph!a-;i);ax!u@Gjla^vNU#fvov=yv2Zc6w6HL7v2-?dGcq-CGPScIq+)WS Gv@`&moHM)t diff --git a/data/handouts/Images/angles-Ssa-proof-isosceles.pdf b/data/handouts/Images/angles-Ssa-proof-isosceles.pdf index 4a85fa4bac925bf00ae953873a33f5a0665bca00..de36d79bffe98d6b89fcf663f45eb1d9e225aef5 100644 GIT binary patch delta 212 zcmcbmbxUi*W`17t5F;ZiV*@KgBW(kN$p`rL&_sUozgKf~b2BtGur$_nb8&UlwRCed z)^%|QUxyE<8#8XG#B89N#qnY#e(F>y3>HMDTHaI&)@ Kq++tYs5Af)*fh-m delta 212 zcmcbmbxUi*W`17F5CcOiLklZo18oDN$p`rL&_sUozgJ7Lw6rj_Of=UuNwG-NH8e~! z)HMJCT}wmDBnyKib8|!URCWEy5BbzKn+aZJ)Uh-$G_(L4sBU1OuF0kEo1fy6SdyyY zVr67tWM*J$fKaj7T=*EHlZ&~zi<_CTo4JXTrIWLZqk*xZn~9sNiJ`fhlYybDp`8sO J6_f2nr2(0FHU9tr diff --git a/data/handouts/Images/angles-Ssa-proof-one-solution.pdf b/data/handouts/Images/angles-Ssa-proof-one-solution.pdf index 7fb3c88bdfe1fb9913d9586eaf5b7afd28e9d6c7..9cc5912751c01680f3849715271e7fc99e73a831 100644 GIT binary patch delta 233 zcmdm}wNYzB3qP-Uh>?+%v4NGLk+y-saB8x|tgqI-BXb8k-sF8o3#` z=sLPs8tA$>JGq*;7`PZ1xVlVM;Mds9E_j1c$K1%s*Z^#tx`BbZCYQc%eu_(CNvej6 zm63swnSrSRLd9lo;ggK9MvhMAhDOdtX67z#2F3=amS(2Lj^=JoW=4*th9<6Nb~Xf6 e#B$l$aTS*&7L`;KrKWM20v*7ms_N?R#svUpkT`q* delta 233 zcmdm}wNYzB3qP-Ah=HM%p@o&Pxwe7PW30B%7F<8=32xq*$cs8XBe< z>KXunu7#y(ikW$mfw56?;$#JWjm_+WHyCv+4Gaw}z{aT?7^rJ<>HFrVxFnXOYPeV# z85o%vm>M8dY~~g|$r$ToY3gR+YH4h4WNP5%V(tv2jm(WKOdKs;EX_^Ko$YK0s)*&X cv*Ri*Nh~U^a}05$YE!TsgPbpr!+O)h=k{1lhOl2i>B zDEC4GU`|w7#doDO;a~8P}k(r_svgnNi0d#aIrEn zFfubRH9)A?tSh0%}+9TU~B=Dvv9I-F>*DxbTe>qG_^1{b#yUwv$G+jV)9%m FX#iStGy?zt diff --git a/data/handouts/Images/angles-alternate.pdf b/data/handouts/Images/angles-alternate.pdf index 67b988609a1d4de9c41b363fff31273bf5a29f58..d8f23d77bb5489a954614e1127d707c20d77c33f 100644 GIT binary patch delta 210 zcmdlWx?+%v4NGLk+y-sWK}jjG?4_hJt`J1X6BYAh8DVx=H_m?ZidFr zx|XJrD+w{&r{v@kVwHF9=yG&M6caW=NIA*dpj%g&CgxFoTtq@pM_jmyZy$dpS})z#mP F3jheBFy;UN delta 210 zcmdlWx)h->u!M-V9udfH6ey6<6-|nw2!H3L6=Sa!XuVl~B$` gQIRJ|ByBePD=Lv?;!v;l^>M%1iWm$E-!B&|-dBD(v;Y7A delta 235 zcmX?XeAsxy8DU<_5CcOiLo+K=18oDN$v1`d&_qN;-m96Xq@`G-C7S7)04ZHV!!$!( z10c{fPfW5jvrJ1eGdDI-*PlF3L~XOb=xIhBO9MkgGq8c`1_tVyT>8HGDK3d6sTwX; zMg~S^2BroG6`S3}6_{ep%?&La-Hgo5Ee%XeO-+oP99>*Z3`|W-oXjoF99>N8YzV4| e<+8KmDlSPZDyb++P2(~%urT6MRdw}u;{pIfuR6#8 diff --git a/data/handouts/Images/angles-complementary-in-triangle.pdf b/data/handouts/Images/angles-complementary-in-triangle.pdf index 37380ab744be32a1007b0307dbfbca62688c1267..fd2e21005bca2dbb041ea400f2d0997ffecbc6b3 100644 GIT binary patch delta 193 zcmeA$>@eIgQ;63*#K_3X*ucurNZY_*@-iVkG?9lw@70`)j7(kKOpSC6Obr}$4K0n# zb~`%91We#OwCLz%?#D`Cua+*ZI%(a&B$eLWMpgrF_2MA0*Sj>S&W0p$ delta 193 zcmeA$>@eIgQ;63x#K6$X(9FuzT-(5C@-iVkG?9lw@6{}fj4TsVjLdXRQY_MR4Gq%_ zbq#<(*T~Gk*wobAB0166TwQ;1wy@e}8IjwJT$ToghGq~08O0=!xSN&5IGCIqjg5>< o4UC-(oSmH=O$?1KTwN{Q42(=19o09K4HiU0rr diff --git a/data/handouts/Images/angles-complementary-parallel-solution.pdf b/data/handouts/Images/angles-complementary-parallel-solution.pdf index cdcfa052e75706dd36398932d9f3939d734b88ce..8520117c63845b1e8e862087efbe108442be6c8c 100644 GIT binary patch delta 216 zcmcbwd0%sb0za>Lh>?+%v4NGLk+y-sWL`vWDq^|p?6`_c5{pVIic-_KOe~EJ LxKveL{oS|#nA9}Y delta 216 zcmcbwd0%sb0za>1h=HM%p}CcTiMD~!WLiDtScDHdtEhK6Z| zx&}a?Yiwa+nP_5WnrfPApsqjJk56s$Vu6Q@T$ToghUO3h`-CKrxSKZ!U1E%NGIen_ zaB*@nb~H6`G&40faWOV=GIlbxG;wk^wRAJHvmvM=mdnnLtGFbwsHCDOHI2)}(%67Y KRn^tsjSB#9l{R7k diff --git a/data/handouts/Images/angles-complementary-parallel-statement.pdf b/data/handouts/Images/angles-complementary-parallel-statement.pdf index cf46a14aecd70250a9380a246286c9f917bc7968..275b801fcd7fe59ecfd0490234fc446b1f307068 100644 GIT binary patch delta 235 zcmdm>v_WY@GdHh!h>?+%v4NGLk+y-saD$xfoiQSi0z%nz~u&8n`){ z=$e|FTI#x*yO^3=7+Shn7#phVPu|F-wwaCh5u=W|k&&?h*g$my19eRv_WY@GdHhgh=HM%p}Cczp|*k1X?9S{SBU7@6ssq*$cs8XBe< z>KXunu90yXP|Ct0$vDwcU4QaMF15{UypI@lEDa0|&A|q$8yKi-a_Rf#r?@1Rq-wZW z85tOv8JHR%RBRUE-_IE9?Cj=bVr*byX=Y;NWM<-Q;p}W`?r7+2gw;t1puU!I%EI< diff --git a/data/handouts/Images/angles-corresponding-alternate-supplementary-connection.pdf b/data/handouts/Images/angles-corresponding-alternate-supplementary-connection.pdf index 0ba660c3bcdce5d33b4b190d3e7b91d1aaa7d7d7..4cda796ac8bc95f8bce75043251b0064ad455e58 100644 GIT binary patch delta 216 zcmcbta#>|V5f86?+%v4NGLk+y-sA{fO`VO*EKCiZ+}sS^oLr1eUCqrLo$YK0s)*&Xv*Ri*Nh~U^a}0IaDtp#T5? delta 216 zcmcbta#>|V5f86rh=HM%p}Cczg|>mw0n4Bpa`Jh>?+%v4NGLk+y-sWHmNDG?7HMJt~goCaz{K=BBz%&K4%RCgwnv ztC^*^a} E0Qep-?EnA( delta 209 zcmdlex>0n4Bpa_~h=HM%p}CcjiMD~!WHmNDG?7HMJt~$)CWaQtiDtScDHdtEhK6Z| zx&}a?o1BzpZkUvqYGi6*wAqpU86%gafuW%}#3(~f2_)|3U`{5+7!zX`BU3|Hb0;HH zGdDwHXH#c$7iS|N&%oKx%+1lx#*&bVSS~v|uHur!qLPZD)HE(56C*P&RaIAiH!c90 CSTW`R diff --git a/data/handouts/Images/angles-equilateral.pdf b/data/handouts/Images/angles-equilateral.pdf index c49b5aa97e5ccb7a71788aa5ec8bab8dfe7ff66d..b8c41c3d5ba51d49c2288fcefafefa0eb826f44c 100644 GIT binary patch delta 212 zcmca&cExOip(w9;h>?+%v4NGLk+y-sWIItkG?7Zt_iAp2u1-!yPUgDC&Q4CcE{4V? zx)uh`=DG&PX2yn27DmPfCMN3oljB9yHg6F-%cx^+1QY@rsBU1OuF0kEo1fy6SdyyY zVr67tWM*J$fKah{t%Mhole4LjvxSqHv$Ly(ql>eVo0E~5p}DJpsj-2%rJ0eTg`Eu{ J6_YKcr2*+VGbjK6 delta 212 zcmca&cExOip(w9qh=HM%p}Cc@p|*k1WIItkG?7Zt_iC1AW+{n@MrOJuDHdtEhK6Z| zx&}a?n`&-kl4NOa0R#r>`jg{D)HZJsJIknJX<%q*4mMETz(8G-OW!v?#U-&MRl~)~ z$iT?Vz|;VtV)I%FFD54gOJj3WBU1}wBSU9rV@qQr6ALGEM-x*g3j-q;S7RqT8$v23 ITS`j<0A<`WtpET3 diff --git a/data/handouts/Images/angles-isosceles-right-triangle.pdf b/data/handouts/Images/angles-isosceles-right-triangle.pdf index 18db95325eb4ea1494b256d4173cd55eb1b91262..d50cb6678a9168d443206672a17d611dc24e4638 100644 GIT binary patch delta 183 zcmdm`zDs=r4b6qzB zH)maAM>k6oGfQV@XD2gt{mHla)He6<-(lo1H!y*iRUjw@=WL!Nc$(44*u==q)zHbr k)!E3{!ra2h+0ES2)WyWrz}V5)#nsHr&W4bR$@7J!0X$eN=>Px# delta 183 zcmdm`zDs=r4h(LtO(P z&^0$VHcd=1OtCaDPgK{Re49^ga}WO=Mh;UWV~AM=f>LnK=1GF58J%2>91YFgOq`t! j9W7m)oDB@kOx%nuT-@9YES#MjjZExp2&tGnUsxIdsuV5! diff --git a/data/handouts/Images/angles-isosceles-triangle.pdf b/data/handouts/Images/angles-isosceles-triangle.pdf index 67e9be21dda2cfa83966ad2ed235ee9d09ae23e1..8a3b542b4f7edccaa9f6555a2017cba1ca91f406 100644 GIT binary patch delta 216 zcmeyb@?T}cJ04#15F;ZiV*@KgBW(kN$-jB@&_v95->aE9TbLOeI2!4?nK--XT9}xc z=o-2hnd-V3S-6n_wz-h+3L}@fk&&?h#6W)m2_)|3LV=Bpv989Z zZsvxjuFe+b#!k+b<}Qwomgdd|W)?=~&gO2WE_OBqRm5`H*>M$@Bo>ua6s4wdnHZZG MajB}h`nz!f0Q1o{mH+?% delta 216 zcmeyb@?T}cJ04!k5CcOiLvt$=Gi?K-$-jB@&_v95->X@snWma2C7S7)q*$cs8XBe< z>KXunZkj=2s)?m(vZ0YllDhun1H5XR3;C`va#?+%v4NGLk+y-sk delta 191 zcmdmDvc+UWsR*xSh=HM%p}Cc*v9^KH?+%v4NGLk+y-s6d-m4j!Sem-JI=ksQ8kt$>8kiVc z=o%RtyXiU`ni?A#yEwTTn_H^uPfie5+bk$?iIL0P$jI0LV&Gdz2_)`jeyP`tPHwJ_ qrp^}5=5CITM#jzt=FS#Q7LLZIrY4RCF2-i&7Irp-R7|#!kp=+pY%lKs delta 193 zcmca^aou7=pBS%Yh=HM%p@o%!p|*k16d-m4{An53Dc7@6ssq*$cs8XBe< z>KXunu91m}aavNEk(ps)qPqU%1aY;^f)bY)xhxF~4J{xBzLk_f;%?@bdd=wMXlw%1 nX<=z(;$&#%Y~teLXy#(#YHsObVrb}OVrpb(LrBGB8yRT;jMOmC diff --git a/data/handouts/Images/angles-polygon.pdf b/data/handouts/Images/angles-polygon.pdf index 7dc7ff90de5881d0d1227a9d3b24107dced47e56..2fac12f6c9dd0606516b23777c0d392759010187 100644 GIT binary patch delta 216 zcmbPWJi&OwO<`X15F;ZiV*@KgBW(kN$6)9HyXab28d{jTIk}n{n_H^uPhKsewmC-hBqNu(k&&?h#6W#<2_)|3K=DV6u@>fL zM$XQLu7+;r=B7@@j!q_)K+{c4Eu9>ljGQga?Q96Dh~=`g<0>vmEGnreN=@T3Gq5z| LQdM>JcjE#85J5FX delta 216 zcmbPWJi&OwO<`Wk5CcOiLklYd3vC0V$KXunu7RbwX=0+GS(3SNs=EH<)go$}V?<9fa#zbOo zxayiYI$G))IlCB`IUAX|Sh^Z-RuuWf$ZcqBXl!f(F-%TO9GSn_L5zpV$<)ov(AC8d ksKd~}(!kuwz|GOX#K76r$lS=t)y&n@&W4bR$$b*i0FO2;Jpcdz delta 191 zcmZ2!xYBULQ6WA9%Mb%YD?sPj4ajlCtnm$+pH#hmXXWc$jI0LV&Gp92_)`jc~L$lCl_-w ppgE2frq0F&F2;t2rY43iZsw*=&K5>yZswK-b~c1mOwJdV1^|YvF8=@k delta 193 zcmeCu@6z9}SdiB;#K6$X(89{dSlhs8@&-XYG?CYW@70n_&616ijm&jTQY_MR4Gq%_ zbq#<(*UZSk(9qN(%`!R7L|uRKMFF+VYQkq3xh#Rg77zpfibx=FH_MCiF*!LJnmbt- nS(+NUnH!lH7(1IA8kn297@C+GnVOm!89Lh85K=KYUtAgh^YSlQ diff --git a/data/handouts/Images/angles-sss-proof.pdf b/data/handouts/Images/angles-sss-proof.pdf index 5d7be237c92543be138ac31be6614ed2705091a1..c7d5a55e8a8bdccdc91ce303b54229d833998a35 100644 GIT binary patch delta 235 zcmajXF$%&!5I|A1T(pW<+r%guGnvV3vOxl7H`}R=oum-dR?rmQL+~7mmk_KxiB}M8 z1RLAW<6rTLmzmRy7l}uxb=w#yTY-dAI fMJ$({9anKlVo^y&QED2OsimnIm#V6(zZ(|-5LY|M diff --git a/data/handouts/Images/angles-supplementary-derive-vertical.pdf b/data/handouts/Images/angles-supplementary-derive-vertical.pdf index 7cbbe0265a27dee4e5876e3ffc3b1655f5eea46e..89a006cb37e56fae64a3aa461cc3857754ddbaee 100644 GIT binary patch delta 215 zcmdm>wLxoxAV05ph>?+%v4NGLk+y-sWI294G?7UD_iCHThOWBCE@m#eX3l0# zx<+PBrn+vXuBH~QmZs*WZf5HGlkNG`Hct__&&XwNWMpgrF|bxh0*SkMzK|(XjH#iy ziIbb9ld*-Fle4jtn~{mJlcR;HlZlI&sf&||os9`06|r1)c3j0JiA5z9MX70ACYFYV LT&k+B{%%|V^N=&? delta 215 zcmdm>wLxoxAV05Vh=HM%p@o&HrM7|5WI294G?7UD_iD+BsfK1|M&`OEDHdtEhK6Z| zx&}a?YiVwhl9+0lXl|Nfs;)oTo=-0mI+`1q8yYzo7&zP6m=IDC%VlTBRa}x-R8motn#N^fX=uo$ Ks_N?R#svVN|1`A# diff --git a/data/handouts/Images/angles-supplementary.pdf b/data/handouts/Images/angles-supplementary.pdf index a9620262b8038b5a5333c11dbdf6665417318f2d..64cebb3c2b4c5ad878e3cd85e0b2f0700a43c89e 100644 GIT binary patch delta 212 zcmew<@>68PLsnk%5F;ZiV*@KgBW(kN$?sV8&_p!Z_NbYgn;4loSs3Y>IhwlaIy;+L z>N+_(JL$TaIl5R{8W@|H89S=$Pi|mS+ib|bk5R|m$jI0LY@oV68PLsnkP5CcOiLrW_I6Kw;d$?sV8&_p!Z_NXPNq$Hb~C7SD+q*$cs8XBe< z>KXunuBm~sS+Y@*k-1Tdg}VOa1~#?LhV1(obu0}G4K2Y2sv8)nYjWxP=BKzMmZWO9 zSQ!}@nHiWGAXIFY=451aGH^CEHM2A}v@o|cGIe%zGB9^GH8L?ZcQiD%Fmf@pu(Khg JVsadpGyupEGh_e& diff --git a/data/handouts/Images/angles-triangle.pdf b/data/handouts/Images/angles-triangle.pdf index d15e7088a9de4ee2a31068408829f34be31625df..eed60c5ff992f19662d83a0672600dfa7c24ac36 100644 GIT binary patch delta 235 zcmX@BeO7yejR3Djh>@|Ck%5(orM7{=WKRJ-G?5m8_iD~&CQi=AMwYsc#uje6PLAfz zy2dU}=DM!NZpOwI28Kok#^&n!llcVIHt!ca#i(OpWNc&rHc;KbKwXnd-#0(SC9xz` z!v$!Qk(q(10Yb&*t-`w*W1So=EnQ6vEM1+A+{|5EjLck(Tnt=|OwAl!OiayWK gs)*&Xv*Ri*Nh~U^a}00ntE5C8xG delta 235 zcmX@BeO7yejR3D@h=HM%k%5(|nYMw^WKRJ-G?5m8_iBa)mZ?Umi59vhDV7GhhK6Z| zx&}a?Yi?+6kYZqBnP_Qbtgb(qPf%_1e!)|WI+g~8Mh0L5)eQ{PHM#VC^HW?BOHwsl zfHoPK8JHR%RBYZVyqhuB(apff*udG+$<@-*(7?pRz}VQu!o=9n#m&gV+{Mz^&W50h eSS~v|uHur!qLPZD)HE(rLo*95RaIAiH!c7vkU7)< diff --git a/data/handouts/Images/angles-vertical-derive-supplementary.pdf b/data/handouts/Images/angles-vertical-derive-supplementary.pdf index 6c25853564c9d4ec0fb16bc477e80819613ceedf..1511c41e882980187439c61ef48986384c272ae1 100644 GIT binary patch delta 216 zcmcboc28}?VqRYJ5F;ZiV*@KgBW(kN$s2g}&_rJIzE?AJF>`b@v@q8-F|{<)H8D1} z&~*6=a&d8VbT(GkpL~%=ZL=ExeMT;GBO_x2h=Kfq5=h+5hJqIuV=WC$ z94$;8-7MS;jociKoQ;f(T#ZaDEKH5eT@4J3o$PD~s)*&Xv*Ri*Nh~U^a}0D?j_hX4Qo delta 216 zcmcboc28}?VqRX$5CcOiLrW_|6Kw;d$s2g}&_rJIzE?{zPBAhzPc+vxNwG-NH8e~! z)HMJC-89qWq_o5|qf|pP3w8a;7kSh+tMT7w&&D6=&+11V1#lYOs*v!Sz&W50hSS~v|uHur!qLPZD)HE&=Qxj7z KRaIAiH!c8_`ZuTm diff --git a/data/handouts/Images/angles-vertical.pdf b/data/handouts/Images/angles-vertical.pdf index 56f468df799a0fd8d3d955c782c6d79c76d1eb13..3b440135f75ee7c48eb144e681025ebe8c4baca8 100644 GIT binary patch delta 214 zcmajXy9&ZU5I|AVte7HQy3~mxOJ-(w^FoAuLJB*c0tAVq<$b z+%X-~N5T>mI}#mW2ki=A$Qb`kd-lwcwDML~T>8*(ZBg^u=)jc>-Ur>1v~^Jqca~3w z*(>5GNC1A81wgTk%kAalj@R?Tbp%v_`Vvz=k0LD^GGr705lLq(Sd@mq0y&Rpo6Y)< I7;bU)1_LiKb^rhX delta 214 zcmZ23x?FSv9~+;6Wr%^Hm7ygNX&V?#mSNLH7Yb+Fqn2WpoML2QWUgzHVv(k6XqaZG zYXAhg1{RhE7KzEJh9;IN>iUz{v8ip2XWz@HYhY<$XlMyGQr*BnU6V`SH$TNCu_RT) z#mdOQ$jrbLNyTPQPDVyYXICdDXHzF*V^>Epby8}B9|xC#m655HvAMQ^!Q==ILuBq`jy-A?#;%T*ZWgAxmIg*Hy2fs%#=4f4 z&X&4{hK|k_j&2r?=H_nd`jcOAsBNCjd4N&Nz{nJAmb!s~x+a&tZ+?nPVo9ooipby8}B9|xC_m655HiLthU(c}mYLuBq`jy-CIDdxte1}15`CMlMdx`u{nhPnno zpqpf3X>4w3n3!s6X`rq@`4xxS=GmMF7`2RyOu=TU8yKi-a_Rf#r?@1Rq-wZW85tOv z8JHSa8o*R+ZsksAbaFE=buu?La5MrMW@&D2Wa(z$Y+>eTXkubvY-(z3XlFx6#biBR FX#j=1F)9E6