<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://russellgordon.dev/">
    <title>Russell Gordon</title>
    <link href="https://russellgordon.dev//feed.xml" rel="self" />
    <link href="https://russellgordon.dev/" />
    <updated>2024-08-16T14:24:32Z</updated>
    <id>https://russellgordon.dev/</id>
    
        <entry>
            <title>
                Setting an App Icon
                
            </title>
            <updated>2020-09-20T15:10:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/setting-an-app-icon/</id>
            <content type="html">
                &lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/7QmGJTHT5Ac&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; allowfullscreen=&quot;&quot; title=&quot;Setting an App Icon&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;An application icon must be provided in many different sizes.&lt;/p&gt;
&lt;p&gt;Creating these manually is a tedious task. Fortunately, an application exists to solve this particular problem for app developers. Download &lt;a href=&quot;https://apps.apple.com/us/app/icon-set-creator/id939343785?mt=12&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Icon Set Creator now&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Open Icon Set Creator once it is downloaded. The first time it runs, you will be prompted to consider financially supporting the developer. If you end up using this app often, I encourage you to do so. For now, click &lt;strong&gt;No, Thanks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Next you &lt;em&gt;may&lt;/em&gt; see a dialog mentioning a more capable application that the developer also makes for solving the same problem. That app is more than is necessary for now, so you can dismiss the dialog by pressing &lt;strong&gt;No thanks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You need an image that is at least 1024 pixels wide by 1024 pixels high.&lt;/p&gt;
&lt;p&gt;This will typically be a custom-designed icon if you release your app on the public App Store. For your own purposes, any image will do.&lt;/p&gt;
&lt;p&gt;I have a nice image of my dog here, but when I open it in Preview, you can see it is not the right size (square).&lt;/p&gt;
&lt;p&gt;I&#39;ll get a square selection in the image by holding the &lt;strong&gt;Shift&lt;/strong&gt; key down on the keyboard as I move my fingers along the trackpad. To crop the image, I&#39;ll use the keyboard shortcut &lt;strong&gt;Command-K&lt;/strong&gt;. Finally, I&#39;ll save the image using &lt;strong&gt;Command-S&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: To switch between applications quickly, you can use the keyboard shortcut &lt;strong&gt;Command-Tab&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, the image must be dragged into Icon Set Creator. Then press the &lt;strong&gt;Go&lt;/strong&gt; button. You can save the output on your Desktop. A folder named &lt;strong&gt;iOS&lt;/strong&gt; will be created. Open this folder, then drag the &lt;strong&gt;AppIcon.appiconset&lt;/strong&gt; folder to the assets folder in Xcode.&lt;/p&gt;
&lt;p&gt;The existing placeholder for the app icon is named &lt;strong&gt;AppIcon&lt;/strong&gt;. We can delete this.&lt;/p&gt;
&lt;p&gt;Then, we can rename the new app icon we just dragged in, from &lt;strong&gt;AppIcon-1&lt;/strong&gt; to &lt;strong&gt;AppIcon&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s it! When you next launch the application on a device, you will see that it has an icon!&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/setting-an-app-icon/" />
        </entry>
    
    
        <entry>
            <title>
                Keyboard Shortcuts in Playgrounds
                
            </title>
            <updated>2021-09-19T15:51:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/keyboard-shortcuts-in-playgrounds/</id>
            <content type="html">
                &lt;p&gt;Keyboard shortcuts let us reduce the amount of time we spend reaching for the trackpad or a mouse.&lt;/p&gt;
&lt;p&gt;Learn the shortcuts below and gain one of the small but helpful &amp;quot;super powers&amp;quot; of experienced software developers.&lt;/p&gt;
&lt;h2 id=&quot;run-playground&quot; tabindex=&quot;-1&quot;&gt;Run Playground&lt;/h2&gt;
&lt;p&gt;Run the latest version of your code.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-R&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/run-playground.gif&quot; loading=&quot;lazy&quot; alt=&quot;Pressing Command-R runs the latest version of the code shown in a Playground.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;step-through-my-code&quot; tabindex=&quot;-1&quot;&gt;Step Through My Code&lt;/h2&gt;
&lt;p&gt;Step through your code, showing what line is being run, one at a time, when the playground runs.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Shift-Command-R&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/step-through-my-code.gif&quot; loading=&quot;lazy&quot; alt=&quot;Pressing Shift-Command-R runs the latest version of your code, but shows what line is being run along the way.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;show-or-hide-sidebar&quot; tabindex=&quot;-1&quot;&gt;Show or Hide Sidebar&lt;/h2&gt;
&lt;p&gt;Toggle the visibility of the navigation sidebar. Hiding the sidebar provides more space to view your code!&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Option-Command-S&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/show-or-hide-sidebar.gif&quot; loading=&quot;lazy&quot; alt=&quot;Pressing Option-Command-S shows or hides the sidebar.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;increase-text-size&quot; tabindex=&quot;-1&quot;&gt;Increase Text Size&lt;/h2&gt;
&lt;p&gt;Increase the size of text in the code window.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command +&lt;/strong&gt; or &lt;strong&gt;Command =&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/increase-text-size.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command + to increase text size in the code window.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;decrease-text-size&quot; tabindex=&quot;-1&quot;&gt;Decrease Text Size&lt;/h2&gt;
&lt;p&gt;Decrease the size of text in the code window.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command -&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/decrease-text-size.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command - to decrease text size in the code window.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;select-all-text&quot; tabindex=&quot;-1&quot;&gt;Select All Text&lt;/h2&gt;
&lt;p&gt;Select all the text in the code window.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-A&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/select-all-text.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-A to select all the text in the code window.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;re-indent&quot; tabindex=&quot;-1&quot;&gt;Re-Indent&lt;/h2&gt;
&lt;p&gt;For any code that is selected, it will be re-indented.&lt;/p&gt;
&lt;p&gt;This is a great way to clean up your code to make it more readable!&lt;/p&gt;
&lt;p&gt;It can also be a way to spot syntax errors, when opening or closing curly brackets for a code block are missing.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Control-I&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/re-indent.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Control-I to re-indent (re-format) any selected code.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;shift-right&quot; tabindex=&quot;-1&quot;&gt;Shift Right&lt;/h2&gt;
&lt;p&gt;For the line of code the cursor is on, or for a selected block of code, shift the code to the right.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-]&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/shift-right.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-] to shift code to the right.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;shift-left&quot; tabindex=&quot;-1&quot;&gt;Shift Left&lt;/h2&gt;
&lt;p&gt;For the line of code the cursor is on, or for a selected block of text, shift the code to the left.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-[&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/shift-left.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-[ to shift code to the left.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;move-to-end-of-current-line&quot; tabindex=&quot;-1&quot;&gt;Move to End of Current Line&lt;/h2&gt;
&lt;p&gt;Move the cursor to the end of the current line.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-→&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/move-to-end-of-line.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-→ to move the cursor to the end of the current line.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;move-to-start-of-current-line&quot; tabindex=&quot;-1&quot;&gt;Move to Start of Current Line&lt;/h2&gt;
&lt;p&gt;Move the cursor to the start of the current line.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-←&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/move-to-start-of-line.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-← to move the cursor to the start of the current line.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;select-entire-line&quot; tabindex=&quot;-1&quot;&gt;Select Entire Line&lt;/h2&gt;
&lt;p&gt;Select an entire line of code, either above or below the cursor.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Shift-↑&lt;/strong&gt; or &lt;strong&gt;Shift-↓&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/select-entire-line.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Shift-↑ to select an entire line of code above the cursor, and Shift-↓ to select an entire line of code below the cursor.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;block-comment&quot; tabindex=&quot;-1&quot;&gt;Block Comment&lt;/h2&gt;
&lt;p&gt;Toggle a selected block of code between being commented out or active.&lt;/p&gt;
&lt;p&gt;Code that is commented out will not be run by the playground.&lt;/p&gt;
&lt;p&gt;Shortcut: &lt;strong&gt;Command-/&lt;/strong&gt;&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/block-comment.gif&quot; loading=&quot;lazy&quot; alt=&quot;Press Command-/ to toggle a selected block of code between being commented out or being active.&quot; width=&quot;568&quot; /&gt;
&lt;/figure&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/keyboard-shortcuts-in-playgrounds/" />
        </entry>
    
    
        <entry>
            <title>
                Ginger Molasses Cookies
                
            </title>
            <updated>2021-04-21T19:10:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/ginger-molasses-cookies/</id>
            <content type="html">
                &lt;h1 id=&quot;preamble&quot; tabindex=&quot;-1&quot;&gt;Preamble&lt;/h1&gt;
&lt;p&gt;A certain purveyor of coffee in North America sells a ginger molasses cookie that is much loved by my partner and I. After a lot of delicious trial and error, this is our version of that cookie. We daresay it&#39;s as good as and possibly better than the original!&lt;/p&gt;
&lt;h1 id=&quot;preparation-time&quot; tabindex=&quot;-1&quot;&gt;Preparation time&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;2 to 3 hours to let butter soften at room temperature&lt;/li&gt;
&lt;li&gt;½ hour to mix wet and dry ingredients&lt;/li&gt;
&lt;li&gt;1 ½ hours for dough to cool in refrigerator&lt;/li&gt;
&lt;li&gt;1 hour to roll and bake cookies&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;yield&quot; tabindex=&quot;-1&quot;&gt;Yield&lt;/h2&gt;
&lt;p&gt;Approximately 24 to 28 cookies.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: Images shown below were taken when recipe was doubled to yield approximately 48 to 56 cookies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;equipment&quot; tabindex=&quot;-1&quot;&gt;Equipment&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;2 to 4 cookie pans, 43.8 x 29.2 x 2.54 cm&lt;/li&gt;
&lt;li&gt;4 silicon baking sheets, or, parchment paper&lt;/li&gt;
&lt;li&gt;large mixing bowl&lt;/li&gt;
&lt;li&gt;medium mixing bowl&lt;/li&gt;
&lt;li&gt;electric mixer or wooden spoon&lt;/li&gt;
&lt;li&gt;2 cooling racks&lt;/li&gt;
&lt;li&gt;food scale&lt;/li&gt;
&lt;li&gt;whisk&lt;/li&gt;
&lt;li&gt;spatula&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;ingredients&quot; tabindex=&quot;-1&quot;&gt;Ingredients&lt;/h1&gt;
&lt;h2 id=&quot;dry&quot; tabindex=&quot;-1&quot;&gt;Dry&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;295 g all-purpose unbleached white flour&lt;/li&gt;
&lt;li&gt;1 tsp. baking soda&lt;/li&gt;
&lt;li&gt;1 tsp. cinnamon&lt;/li&gt;
&lt;li&gt;2 tsp. ground ginger&lt;/li&gt;
&lt;li&gt;½ tsp. salt&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wet&quot; tabindex=&quot;-1&quot;&gt;Wet&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;170 g unsalted butter, softened&lt;/li&gt;
&lt;li&gt;110 g white sugar&lt;/li&gt;
&lt;li&gt;110 g brown sugar&lt;/li&gt;
&lt;li&gt;1 egg, room temperature&lt;/li&gt;
&lt;li&gt;½ tsp. pure vanilla&lt;/li&gt;
&lt;li&gt;60 g molasses&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;topping&quot; tabindex=&quot;-1&quot;&gt;Topping&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;approximately 250 g coarse dark granulated sugar&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;directions&quot; tabindex=&quot;-1&quot;&gt;Directions&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;About five hours before you wish to complete the baking process, measure out the butter, and place in the large mixing bowl. Chopping the butter into smaller cubes hastens the softening process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;About 2 to 3 hours later, set the egg out to warm to room temperature.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Beat the butter until it is light and airy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/butter.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Butter in a large glass mixing bowl that has been beaten until light and airy.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Using a whisk, combine dry ingredients in the medium mixing bowl.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/dry.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Flour, baking sode, cinnamon, ground ginger, and salt, mixed in a medium stainless steel bowl.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Combine white sugar with contents of large mixing bowl.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/white-sugar.jpg&quot; loading=&quot;lazy&quot; alt=&quot;White sugar combined with butter in a large glass mixing bowl.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;Combine brown sugar with contents of large mixing bowl.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/brown-sugar.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Brown sugar combined with butter and white sugar in a large glass mixing bowl.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;Add egg, vanilla, and molasses to large mixing bowl, then combine.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/rest-of-wet.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Egg, vanilla, and molasses combined with butter and sugars in a large glass mixing bowl.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;Gradually add dry ingredients to wet ingredients. Four rounds of combining dry to wet works well. Dough will be stiff.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/dry-to-wet.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Dry ingredients combined with wet ingredients in a large glass mixing bowl produces a stiff dough that is ready to be chilled.&quot; width=&quot;560&quot; /&gt;
&lt;figcaption&gt;Dough will become stiff as the mixing continues. When complete the dough is ready to be chilled.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;
&lt;p&gt;Set the dough in a refrigerator to chill, covered, for 1 and ½ hours.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pre-heat an oven to 350 °F with convection, or 375 °F without.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the topping, place the coarse, dark, granulated sugar in a low-rimmed bowl.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/sugar-topping.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Coarse, dark, granulated sugar placed in a low rimmed ceramic bowl.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;12&quot;&gt;
&lt;li&gt;Using a small cookie dough scoop (pictured at left in first image) and a butter knife, scoop dough from mixing bowl.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/scooping-dough.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A small cookie dough scoop and a butter knife are used to scoop and level dough.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;Roll the dough between your hands, then gently compress the ball of dough in the granulated sugar, and place on cookie sheet.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/rolling-dough.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Cookie dough is rolled and compressed in the low bowl of sugar to top the cookie.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;14&quot;&gt;
&lt;li&gt;
&lt;p&gt;Repeat steps 12 and 13 until you have 8 cookies per baking sheet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With a convection oven you can bake 16 cookies, one sheet per oven rack. Bake for 15 minutes. While first batch of cookies bakes, prepare the second batch of cookies for baking.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/before-and-after.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Eight cookies pictured before and after baking. After baking, cookies will spread but should not touch one another.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;ol start=&quot;16&quot;&gt;
&lt;li&gt;When cookies have baked for 15 minutes, remove from oven and let cool for 3 minutes, then use a spatula to move to a cooling rack. Allow oven to reheat before placing the next batch in the oven.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/all-done.jpg&quot; loading=&quot;lazy&quot; alt=&quot;All cookies pictured cooling on a wire rack.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;When cooled, cookies should be moderately crisp at the edges, but soft and chewy at their centre. Enjoy! 😀&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/ginger-molasses-cookies/" />
        </entry>
    
    
        <entry>
            <title>
                Getting to Know Core Data
                
            </title>
            <updated>2021-01-03T18:15:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/getting-to-know-core-data/</id>
            <content type="html">
                &lt;p&gt;If you&#39;ve made it to &lt;a href=&quot;https://www.hackingwithswift.com/100/swiftui/61&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Day 61&lt;/a&gt; of Paul Hudson&#39;s &lt;a href=&quot;https://www.hackingwithswift.com/100/swiftui/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;100 Days of SwiftUI&lt;/a&gt; tutorial series then you probably have a healthy appreciation for the quality and value of that &lt;em&gt;free&lt;/em&gt; resource.&lt;/p&gt;
&lt;p&gt;I teach high school computer science in Ontario, Canada. Although our &lt;a href=&quot;http://edu.gov.on.ca/eng/curriculum/secondary/computer10to12_2008.pdf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;curriculum is excellent&lt;/a&gt; student enrolment numbers have never been high enough to warrant interest from textbook publishers. On top of that, any textbook written for a particular programming language or framework would quickly become out of date. So in years past I have often ended up writing all of the material my students work with. Compared to, say, a biology teacher – I write both the textbook &lt;em&gt;and&lt;/em&gt; the lesson plans.&lt;/p&gt;
&lt;p&gt;So I am &lt;em&gt;especially&lt;/em&gt; grateful for Paul&#39;s writing. He has a real knack for explaining topics within a context, in simple terms, often with a dash of humour. I am &lt;em&gt;unequivocally in awe&lt;/em&gt; of the &lt;a href=&quot;https://www.hackingwithswift.com/articles/225/year-in-review-2020&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;volume of his output&lt;/a&gt;. Both myself and my students have found his tutorials to be enormously helpful.&lt;/p&gt;
&lt;p&gt;The core challenge of days 60 and 61 is to &lt;a href=&quot;https://www.hackingwithswift.com/guide/ios-swiftui/5/3/challenge&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;build an application that shows user data to illustrate connections between friends&lt;/a&gt;. At first, user data &lt;a href=&quot;https://www.hackingwithswift.com/samples/friendface.json&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;pulled from the remote JSON file&lt;/a&gt; is stored entirely in-memory. Later we are asked to &lt;a href=&quot;https://www.hackingwithswift.com/100/swiftui/61&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;modify the application so that data is kept inside a Core Data store&lt;/a&gt; – in this way, it would not be necessary to load the JSON file from the remote server each time the application opens.&lt;/p&gt;
&lt;p&gt;In my experience Paul scaffolded concepts well leading up to this task – he provided prerequisite tasks that build necessary skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;On days 49 through 52 we built the &lt;a href=&quot;https://www.hackingwithswift.com/books/ios-swiftui/cupcake-corner-introduction&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Cupcake Corner&lt;/a&gt; app which involved sending and retrieving JSON to a remote server.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On days 53 through 56 we built &lt;a href=&quot;https://www.hackingwithswift.com/books/ios-swiftui/bookworm-introduction&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Bookworm&lt;/a&gt; which involved writing an app to track books a person has read and their rating for each title. Information was stored in a Core Data store.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On days 57 through 59, we built a &lt;em&gt;technique project&lt;/em&gt; – essentially a series of small examples of functionality – that methodically illustrated concepts we&#39;d need to employ later on – such as using the &lt;a href=&quot;https://developer.apple.com/documentation/foundation/nspredicate&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NSPredicate class&lt;/a&gt; or understanding &lt;a href=&quot;https://www.hackingwithswift.com/books/ios-swiftui/one-to-many-relationships-with-core-data-swiftui-and-fetchrequest&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;relationships between entities&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said, from what I have read on Twitter and in the &lt;a href=&quot;https://www.hackingwithswift.com/forums/100-days-of-swiftui/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;discussion forums Paul operates to support learners&lt;/a&gt;, there is a sense that learning Core Data is hard and that the Day 61 challenge can be especially tricky.&lt;/p&gt;
&lt;p&gt;Additionally, changes to how the SwiftUI application lifecycle works as of Xcode 12 – released after Paul wrote these tutorials – provide additional wrinkles.&lt;/p&gt;
&lt;p&gt;On that note, the purpose of this post is to share:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;solutions to some of the roadblocks I encountered&lt;/li&gt;
&lt;li&gt;a few tips to make debugging with Core Data easier&lt;/li&gt;
&lt;li&gt;some links to additional resources that were especially helpful&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;end-product&quot; tabindex=&quot;-1&quot;&gt;End Product&lt;/h2&gt;
&lt;p&gt;Here is a brief overview of what my &lt;em&gt;Friends&lt;/em&gt; app looked like when it was complete:&lt;/p&gt;
&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/9t5RUdNmjJo&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; allowfullscreen=&quot;&quot; title=&quot;Getting to Know Core Data&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I modified the core challenge in the following ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;used the &lt;strong&gt;SwiftUI App&lt;/strong&gt; life cycle option, rather than &lt;strong&gt;UIKit App Delegate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;loaded user data at the application level, &lt;em&gt;prior&lt;/em&gt; to the appearance of the first view or window&lt;/li&gt;
&lt;li&gt;pulled down images of users from &lt;a href=&quot;https://randomuser.me/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Random User Generator&lt;/a&gt; service&lt;/li&gt;
&lt;li&gt;added a second view so that the app supports the notion of marking friends as belonging to an &amp;quot;inner circle&amp;quot; of close friends&lt;/li&gt;
&lt;li&gt;made it possible to use Xcode Previews with a smaller set of user data loaded into an in-memory Core Data store&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;swift-ui-app-life-cycle-and-the-provided-template&quot; tabindex=&quot;-1&quot;&gt;SwiftUI App Life Cycle and the Provided Template&lt;/h2&gt;
&lt;p&gt;The first bump in the road came when I chose to create my Friends app &lt;a href=&quot;https://russellgordon.dev/tutorials/creating-a-new-xcode-project-for-a-swiftui-app/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;using the newer &lt;strong&gt;SwiftUI App&lt;/strong&gt; life cycle option&lt;/a&gt;, rather than the &lt;strong&gt;UIKit App Delegate&lt;/strong&gt; option that I&#39;d used when following Paul&#39;s tutorials in the lead-up to days 60 and 61.&lt;/p&gt;
&lt;p&gt;In theory, Xcode provides templates to get developers moving from common starting points.&lt;/p&gt;
&lt;p&gt;Using Xcode 12.3, after creating a new project using the &lt;strong&gt;SwiftUI App&lt;/strong&gt; lifecycle option, and ensuring that the &lt;strong&gt;Use Core Data&lt;/strong&gt; option was enabled, I built and ran the project. Here is what I saw:&lt;/p&gt;
&lt;figure style=&quot;width: 324px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/core-data-example-project.png&quot; loading=&quot;lazy&quot; alt=&quot;Running the example project in Xcode 12 for an iOS app with Core Data enabled results in a blank view.&quot; width=&quot;324&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Not a promising start – we should see toolbar buttons that allow us to add and remove items from a list.&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&quot;https://developer.apple.com/forums/thread/661950?login=true&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the solution on the Apple Developer Forums&lt;/a&gt;. Here is a &lt;a href=&quot;https://github.com/lcs-rgordon/CoreDataTest/commit/2bab9716e62b10c35bb0023a1ea864e8ec6596cf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;diff of the changes&lt;/a&gt; and here is the entire &lt;code&gt;ContentView.swift&lt;/code&gt; file that &lt;a href=&quot;https://raw.githubusercontent.com/lcs-rgordon/CoreDataTest/2bab9716e62b10c35bb0023a1ea864e8ec6596cf/CoreDataTest/ContentView.swift&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;corrects the issue&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;tip-enable-core-data-debugging&quot; tabindex=&quot;-1&quot;&gt;Tip: Enable Core Data Debugging&lt;/h2&gt;
&lt;p&gt;When programming a user interface in SwiftUI, we get feedback instantly in Xcode Previews.&lt;/p&gt;
&lt;p&gt;This makes it really fast to iterate and improve a user interface. It&#39;s one of the primary reasons I love working with the SwiftUI framework.&lt;/p&gt;
&lt;p&gt;However, my initial experience programming with Core Data left me wondering &lt;em&gt;exactly what was happening&lt;/em&gt; behind the scenes on a fairly regular basis.&lt;/p&gt;
&lt;p&gt;Did that user record just get added to the Core Data store?&lt;/p&gt;
&lt;p&gt;How could I be sure?&lt;/p&gt;
&lt;p&gt;I needed a way to debug Core Data operations.&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&quot;https://www.donnywals.com/using-launch-arguments-for-easier-core-data-debugging/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;this article&lt;/a&gt; by &lt;a href=&quot;https://www.donnywals.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Donny Wals&lt;/a&gt; and it was super helpful.&lt;/p&gt;
&lt;p&gt;For the rest of my time completing the day 61 challenge, I ran my project with this launch argument enabled:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;-com.apple.CoreData.SQLDebug 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was enough to help me see what was happening with Core Data behind the curtain.&lt;/p&gt;
&lt;h2 id=&quot;loading-user-data-at-the-application-level&quot; tabindex=&quot;-1&quot;&gt;Loading User Data at the Application Level&lt;/h2&gt;
&lt;p&gt;It seems pretty clear to me that with the days 60 and 61 challenge, Paul intended for learners to parse the JSON and eventually load that information into Core Data using the &lt;code&gt;.onAppear&lt;/code&gt; modifier of the first view – we were told as much when &lt;a href=&quot;https://www.hackingwithswift.com/books/ios-swiftui/how-to-combine-core-data-and-swiftui&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;setting up the Bookworm app&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All our managed objects live inside a &lt;em&gt;managed object context&lt;/em&gt;, which is the thing that’s responsible for actually fetching managed objects, as well as for saving changes and more. You can have many managed object contexts if you want, but that’s quite a way away right now – realistically you’ll be fine with one for a long time yet.&lt;/p&gt;
&lt;p&gt;We don’t need to create this managed object context, because Xcode already made one for us. Even better, it already added it to the SwiftUI environment, which is what makes the &lt;code&gt;@FetchRequest&lt;/code&gt; property wrapper work – it uses whatever managed object context is available in the environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even when using the newer the &lt;strong&gt;SwiftUI App&lt;/strong&gt; lifecycle, we&#39;re in good shape based upon what the Xcode template provides.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;ProjectNameApp.swift&lt;/code&gt; file (where &lt;code&gt;ProjectName&lt;/code&gt; is whatever name you selected when creating the project in Xcode), there is this code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;@main
struct FriendsApp: App {
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(&#92;.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.environment&lt;/code&gt; modifier on &lt;code&gt;ContentView&lt;/code&gt; injects the managed object context into the environment, so that it is later available to SwiftUI views through the &lt;code&gt;@Environment&lt;/code&gt; property wrapper, just like in the earlier tutorials from Paul:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;@Environment(&#92;.managedObjectContext) var moc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what&#39;s the problem?&lt;/p&gt;
&lt;p&gt;Well, I decided that I &lt;em&gt;didn&#39;t&lt;/em&gt; want to parse the JSON file and load it into Core Data on the first view my app presents.&lt;/p&gt;
&lt;p&gt;This speaks to &lt;em&gt;separation of concerns&lt;/em&gt;. I know that it&#39;s generally not ideal to closely tie together the parts of your app that store data with the parts of your app that display the data.&lt;/p&gt;
&lt;p&gt;I should have just rolled with it. I would have made my life easier. I expect that in a future tutorial, Paul will show learners how to better separate code for handling data from code for handling the user interface.&lt;/p&gt;
&lt;p&gt;I didn&#39;t roll with it.&lt;/p&gt;
&lt;p&gt;If you want to talk to Core Data outside of a SwiftUI view you need to know where to find the managed object context.&lt;/p&gt;
&lt;p&gt;In the template Xcode 12 provides, that is via the &lt;code&gt;PersistenceController&lt;/code&gt; struct from the &lt;code&gt;Persistence.swift&lt;/code&gt; file. A static property provides access to a managed object context that runs on the main thread of an app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;PersistenceController.shared.container.viewContext
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My next question was how to best load user data &lt;em&gt;directly&lt;/em&gt; into Core Data.&lt;/p&gt;
&lt;p&gt;One &lt;em&gt;could&lt;/em&gt; decode the JSON into structures that exist in memory, and &lt;em&gt;then&lt;/em&gt; load the data in those structures into Core Data objects, but that does not sound terribly memory efficient.&lt;/p&gt;
&lt;p&gt;So how could I get the data &lt;em&gt;directly&lt;/em&gt; into Core Data from the external JSON file?&lt;/p&gt;
&lt;p&gt;I really didn&#39;t know how that might be done.&lt;/p&gt;
&lt;p&gt;With some looking, I once again found a &lt;a href=&quot;https://www.donnywals.com/using-codable-with-core-data-and-nsmanagedobject/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Donny Wals article that provided an answer&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;decoding-json-directly-into-core-data-objects&quot; tabindex=&quot;-1&quot;&gt;Decoding JSON Directly into Core Data Objects&lt;/h2&gt;
&lt;p&gt;Essentially, decoding JSON directly into instances of Core Data classes is pretty much identical to decoding JSON directly into instances of structures or classes that you define yourself. You just need to provide a managed object context for the &lt;code&gt;JSONDecoder&lt;/code&gt; class so that it can talk to the Core Data store.&lt;/p&gt;
&lt;p&gt;So now, within the shared data task of &lt;code&gt;URLSession&lt;/code&gt;, after pulling the JSON data down from Paul&#39;s website, I was kicking off parsing the JSON into Core Data with this segment of code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Now decode from JSON directly into Core Data managed objects
let decoder = JSONDecoder(context: PersistenceController.shared.container.viewContext)
if let decodedData = try? decoder.decode([CDUser].self, from: unwrappedData) {
	print(&amp;quot;There were &#92;(decodedData.count) users placed into Core Data&amp;quot;)
} else {
	print(&amp;quot;Could not decode from JSON into Core Data&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My &lt;code&gt;CDUser+CoreDataClass.swift&lt;/code&gt; file looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;//
//  CDUser+CoreDataClass.swift
//  Friends
//
//  Created by Russell Gordon on 2020-12-27.
//
//

import Foundation
import CoreData

@objc(CDUser)
public class CDUser: NSManagedObject, Decodable {

    // What properties to decode
    enum CodingKeys: CodingKey {
        case id
        case isActive
        case name
        case age
        case company
        case email
        case address
        case about
        case registered
        case tags
        case friends
    }

    required convenience public init(from decoder: Decoder) throws {
        
        // Attempt to extract the object
        guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else {
            fatalError(&amp;quot;NSManagedObjectContext is missing&amp;quot;)
        }
        
        let entity = NSEntityDescription.entity(forEntityName: &amp;quot;CDUser&amp;quot;, in: context)!
        
        self.init(entity: entity, insertInto: context)
        
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        id = try container.decode(String.self, forKey: .id)
        isActive = try container.decode(Bool.self, forKey: .isActive)
        name = try container.decode(String.self, forKey: .name)
        age = try container.decode(Int16.self, forKey: .age)
        company = try container.decode(String.self, forKey: .company)
        email = try container.decode(String.self, forKey: .email)
        address = try container.decode(String.self, forKey: .address)
        let untrimmedAbout = try container.decode(String.self, forKey: .about)
        about = untrimmedAbout.trimmingCharacters(in: CharacterSet(charactersIn: &amp;quot;&#92;r&#92;n&amp;quot;))
        
        // Decode the date
        // SEE: https://developer.apple.com/documentation/foundation/dateformatter#overview
        // SEE: https://developer.apple.com/documentation/foundation/iso8601dateformatter
        // SEE: https://makclass.com/posts/24-a-quick-example-on-iso8601dateformatter-and-sorted-by-function
        let dateAsString = try container.decode(String.self, forKey: .registered)
        let dateFormatter = ISO8601DateFormatter()
        registered = dateFormatter.date(from: dateAsString) ?? Date()

        // Decode all the tags and tie to this entity
        let tagsAsStrings = try container.decode([String].self, forKey: .tags)
        var tags: Set&amp;lt;CDTag&amp;gt; = Set()
        for tag in tagsAsStrings {
            let newTag = CDTag(context: context)
            newTag.name = tag
            // Associate each tag in the set with this user
            newTag.tagOrigin = self
            tags.insert(newTag)
        }
        tag = tags as NSSet
        
        // Decode all the friends and tie to this entity
        let friends = try container.decode(Set&amp;lt;CDFriend&amp;gt;.self, forKey: .friends)
        for friend in friends {
            // Associate each friend in the set with this user
            friend.friendOrigin = self
        }
        friend = friends as NSSet
                
    }
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However... I was now seeing very odd behaviour.&lt;/p&gt;
&lt;p&gt;Sometimes, 100 users, as expected, would be loaded from the JSON file into Core Data.&lt;/p&gt;
&lt;p&gt;And sometimes, 99 users would be loaded. Or 98.&lt;/p&gt;
&lt;p&gt;Or on occasion, the app would just crash. 😕&lt;/p&gt;
&lt;h2 id=&quot;tip-enable-concurrency-debugging&quot; tabindex=&quot;-1&quot;&gt;Tip: Enable Concurrency Debugging&lt;/h2&gt;
&lt;p&gt;I tend to become laser focused on solving one problem while programming when instead I should take a step back and examine the larger picture. Or... maybe just read resources that I come across more carefully.&lt;/p&gt;
&lt;p&gt;Had I read a bit further in the Donny Wals article on &lt;a href=&quot;https://www.donnywals.com/using-launch-arguments-for-easier-core-data-debugging/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;using launch arguments for Core Data debugging&lt;/a&gt;, I would have found this key paragraph (emphasis and link mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the biggest frustrations you might have with Core Data is random crashes due to threading problems. &lt;em&gt;You&#39;re supposed to use [the] managed object context and managed objects &lt;a href=&quot;https://developer.apple.com/documentation/coredata/using_core_data_in_the_background&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;only on the threads that they were created on&lt;/a&gt;, and violating this rule might crash your app.&lt;/em&gt; However, usually your app won&#39;t crash and everything is fine. But then every now and then a random crash pops up. You can tell that it&#39;s Core Data related but you might not be sure where the error is coming from exactly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By enabling this launch argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;-com.apple.CoreData.ConcurrencyDebug 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... you are asking iOS to enforce a contract – you promise, as the programmer, to &lt;em&gt;only use a managed object context on the thread it was created on&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you break that contract, the app will immediately crash (with a rather cute error message of &amp;quot;all that is left to us is honor&amp;quot;).&lt;/p&gt;
&lt;p&gt;This is a far superior state of affairs to having your app &lt;em&gt;sometimes&lt;/em&gt; work and &lt;em&gt;sometimes not&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The problem I had was that I was passing the managed object context for the &lt;em&gt;main thread&lt;/em&gt; of my app to &lt;code&gt;JSONDecoder&lt;/code&gt;, within a shared data task for &lt;code&gt;URLSession&lt;/code&gt; – a task that will be run on a &lt;em&gt;background thread&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;URLSession.shared.dataTask(with: request) { data, response, error in
	
	// handle the result here – attempt to unwrap optional data provided by task
	guard let unwrappedData = data else {
		
		// Show the error message
		print(&amp;quot;No data in response: &#92;(error?.localizedDescription ?? &amp;quot;Unknown error&amp;quot;)&amp;quot;)
		
		return
	}
	
	// Now decode from JSON directly into Core Data managed objects
	let decoder = JSONDecoder(context: PersistenceController.shared.container.viewContext)
	if let decodedData = try? decoder.decode([CDUser].self, from: unwrappedData) {
		print(&amp;quot;There were &#92;(decodedData.count) users placed into Core Data&amp;quot;)
	} else {
		print(&amp;quot;Could not decode from JSON into Core Data&amp;quot;)
	}
	
	// and so on...

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That violates the Core Data concurrency contract.&lt;/p&gt;
&lt;h1 id=&quot;using-background-threads-and-loading-user-images&quot; tabindex=&quot;-1&quot;&gt;Using Background Threads and Loading User Images&lt;/h1&gt;
&lt;p&gt;I will save you the tortured play-by-play recounting of my experience at this point.&lt;/p&gt;
&lt;p&gt;To summarize, I eventually found this &lt;a href=&quot;https://developer.apple.com/documentation/coredata/loading_and_displaying_a_large_data_feed&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;example project provided by Apple&lt;/a&gt; that illustrates best practices for loading JSON into Core Data on a background thread.&lt;/p&gt;
&lt;p&gt;In the final version of my Friends app, within the initializer of my &lt;code&gt;FriendsApp&lt;/code&gt; struct,  I kick off loading user data like this, prior to any views being displayed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Kick off loading users from JSON or Core Data
_ = DataProvider()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is what &lt;a href=&quot;https://gist.github.com/lcs-rgordon/01cff5a68d75c58fd3ef7ad216b3a252&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;my DataProvider class looks like&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notice that each time operations are performed with Core Data, they occur on a &lt;a href=&quot;https://developer.apple.com/documentation/coredata/nspersistentcontainer/1640581-newbackgroundcontext&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;background managed object context&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;fetchAndSaveAvatars()&lt;/code&gt; method you will see how user images are loaded.&lt;/p&gt;
&lt;p&gt;Again, note that a background managed object context is created within the shared data task on &lt;code&gt;URLSession&lt;/code&gt;. This occurs 100 times, since there are 100 users.&lt;/p&gt;
&lt;p&gt;It will not work to create a background managed object context outside the shared data task – that breaks the Core Data concurrency contract.&lt;/p&gt;
&lt;h2 id=&quot;additional-resources&quot; tabindex=&quot;-1&quot;&gt;Additional Resources&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier, I extended the day 61 challenge a bit further by adding the notion of an &amp;quot;inner circle&amp;quot; of friends presented on a second tab.&lt;/p&gt;
&lt;p&gt;A badge icon is updated as friends are added to the &amp;quot;inner circle&amp;quot; list. The count of items in the badge is reduced once the user of my app views the friend&#39;s details from within the &amp;quot;inner circle&amp;quot; tab.&lt;/p&gt;
&lt;p&gt;At present, it seems there is no direct way to add a notification badge to a tab item in SwiftUI – so we &lt;a href=&quot;https://medium.com/flawless-app-stories/swiftui-tutorial-showing-badge-on-tab-bar-item-d71e4075b67a&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;have to do it manually, as explained here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also found this &lt;a href=&quot;https://nspredicate.xyz/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;NSPredicate cheat sheet to be useful&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, I worked out how to continue using Xcode Previews to refine my SwiftUI views while still using Core Data.&lt;/p&gt;
&lt;p&gt;You are welcome to &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/Friends.zip&quot;&gt;download and browse the code of my finished Friends app&lt;/a&gt; to see how that was done. Xcode 12.2 or later is recommended to open and build that project.&lt;/p&gt;
&lt;p&gt;This article became more lengthy than I intended. 😅&lt;/p&gt;
&lt;p&gt;If you&#39;ve found it useful, or noticed any errors, &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;please let me know&lt;/a&gt;!&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/getting-to-know-core-data/" />
        </entry>
    
    
        <entry>
            <title>
                Creating a New Xcode Project for a SwiftUI App
                
            </title>
            <updated>2020-08-17T15:31:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/creating-a-new-xcode-project-for-a-swiftui-app/</id>
            <content type="html">
                &lt;p&gt;Everyone was a beginner at some point, and this article is for those just starting out.&lt;/p&gt;
&lt;p&gt;For pure SwiftUI apps, there are &lt;a href=&quot;https://www.appcoda.com/xcode-12-swift-53/#SwiftUI_App_Life_Cycle&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;some changes in the app life cycle&lt;/a&gt; in Xcode 12 that affect the creation of a new project.&lt;/p&gt;
&lt;p&gt;So here is a brief description of how to get started with the most basic form of iOS app using SwiftUI in both recent versions of Xcode.&lt;/p&gt;
&lt;h2 id=&quot;xcode-12&quot; tabindex=&quot;-1&quot;&gt;Xcode 12&lt;/h2&gt;
&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/YaV_BQiWJFw&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; allowfullscreen=&quot;&quot; title=&quot;Creating a New Xcode Project for a SwiftUI App&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;From the menu, choose &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;New&lt;/strong&gt; → &lt;strong&gt;Project...&lt;/strong&gt; or use the keyboard shortcut &lt;strong&gt;Shift-Command-N&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now you will choose a project template. In this sheet, select the &lt;strong&gt;iOS&lt;/strong&gt; tab, then &lt;strong&gt;App&lt;/strong&gt;, then press &lt;strong&gt;Next&lt;/strong&gt;:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-template-xcode12-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-template-xcode12-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting a project template.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;The following sheet allows you to select various options for the project. It looks like this:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-options-xcode12-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-options-xcode12-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting project options.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Make the &lt;strong&gt;Product Name&lt;/strong&gt; something concise but descriptive that will allow you to find the project on your computer in the future. Don&#39;t worry – the name you choose here does not commit you to using that same name for what end-users will eventually see for your app on their home screen icon and in the App Store.&lt;/p&gt;
&lt;p&gt;If you see an &lt;strong&gt;Add account...&lt;/strong&gt; button rather than a pop up menu to select a team, then press the button and follow the steps to either log in with, or create a new, Apple ID. This will be helpful later on – having a team specified for your project will permit you to load your app on to devices for testing purposes.&lt;/p&gt;
&lt;p&gt;You can leave the &lt;strong&gt;Organization Identifier&lt;/strong&gt; field with its default value.&lt;/p&gt;
&lt;p&gt;Be sure that the &lt;strong&gt;Interface&lt;/strong&gt; field is set to &lt;em&gt;SwiftUI&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Life Cycle&lt;/strong&gt; field should be set to &lt;em&gt;SwiftUI App&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Language&lt;/strong&gt; field should be set to &lt;em&gt;Swift&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;All of the various checkboxes at the bottom of this sheet can be unchecked.&lt;/p&gt;
&lt;p&gt;Now, press the &lt;strong&gt;Next&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;You will then see a sheet that allows you to select where to save your work. I really recommend being organized about where you save your work on your computer. The sheet looks like this:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-location-xcode12-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-location-xcode12-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting where to save the project on disk.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Be sure to enable source control, so that a &lt;code&gt;git&lt;/code&gt; repository is created, as pictured. More on source control in another post, but basic usage of &lt;code&gt;git&lt;/code&gt; is not hard, and there are many benefits.&lt;/p&gt;
&lt;p&gt;Then, press the &lt;strong&gt;Create&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;That&#39;s it! You&#39;re ready to start building your SwiftUI-based iOS app in Xcode 12. 🚀&lt;/p&gt;
&lt;h2 id=&quot;xcode-11&quot; tabindex=&quot;-1&quot;&gt;Xcode 11&lt;/h2&gt;
&lt;p&gt;From the menu, choose &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;New&lt;/strong&gt; → &lt;strong&gt;Project...&lt;/strong&gt; or use the keyboard shortcut &lt;strong&gt;Shift-Command-N&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now you will choose a project template. In this sheet, select the &lt;strong&gt;iOS&lt;/strong&gt; tab, then &lt;strong&gt;Single View App&lt;/strong&gt;, then press &lt;strong&gt;Next&lt;/strong&gt;:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-template-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-template-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting a project template.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;The following sheet allows you to select various options for the project. It looks like this:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-options-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-options-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting project options.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Make the &lt;strong&gt;Product Name&lt;/strong&gt; something concise but descriptive that will allow you to find the project on your computer in the future. Don&#39;t worry – the name you choose here does not commit you to using that same name for what end-users will eventually see for your app on their home screen icon and in the App Store.&lt;/p&gt;
&lt;p&gt;If you see an &lt;strong&gt;Add account...&lt;/strong&gt; button rather than a pop up menu to select a team, then press the button and follow the steps to either log in with, or create a new, Apple ID. This will be helpful later on – having a team specified for your project will permit you to load your app on to devices for testing purposes.&lt;/p&gt;
&lt;p&gt;You can leave the &lt;strong&gt;Organization Name&lt;/strong&gt; and &lt;strong&gt;Organization Identifier&lt;/strong&gt; fields with their default values.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Language&lt;/strong&gt; field should be set to &lt;em&gt;Swift&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Set the &lt;strong&gt;User Interface&lt;/strong&gt; field to &lt;em&gt;SwiftUI&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;All of the various checkboxes at the bottom of this sheet can be unchecked.&lt;/p&gt;
&lt;p&gt;Now, press the &lt;strong&gt;Next&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;You will then see a sheet that allows you to select where to save your work. I really recommend being organized about where you save your work on your computer. The sheet looks like this:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/selecting-project-location-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-project-location-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Selecting where to save the project on disk.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Be sure to enable source control, so that a &lt;code&gt;git&lt;/code&gt; repository is created, as pictured. More on source control in another post, but basic usage of &lt;code&gt;git&lt;/code&gt; is not hard, and there are many benefits.&lt;/p&gt;
&lt;p&gt;Then, press the &lt;strong&gt;Create&lt;/strong&gt; button.&lt;/p&gt;
&lt;p&gt;That&#39;s it! You&#39;re ready to start building your SwiftUI-based iOS app in Xcode 11. 🚀&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/creating-a-new-xcode-project-for-a-swiftui-app/" />
        </entry>
    
    
        <entry>
            <title>
                Creating a Custom Theme Using Publish
                
            </title>
            <updated>2020-08-13T13:30:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/creating-a-custom-theme-using-publish/</id>
            <content type="html">
                &lt;p&gt;The Swift community is fortunate to have many knowledgeable and generous members, one of whom is &lt;a href=&quot;https://twitter.com/johnsundell&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;John Sundell&lt;/a&gt;, the author of the &lt;a href=&quot;https://github.com/JohnSundell/Publish&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Publish&lt;/a&gt; static site generator.&lt;/p&gt;
&lt;p&gt;This very site is generated using Publish.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;br /&gt;
As of March 2024, this site is published using the &lt;a href=&quot;https://dg-docs.ole.dev/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Obsidian Digital Garden Plugin&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This article will &lt;a href=&quot;https://github.com/JohnSundell/Publish#building-an-html-theme&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;expand on the instructions provided&lt;/a&gt; for creating your own theme, and cover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;duplicating the provided Foundation theme as a starting point for creating your own theme&lt;/li&gt;
&lt;li&gt;adjusting the presentation of content using CSS&lt;/li&gt;
&lt;li&gt;modifying site content using the domain-specific language (DSL) of  &lt;a href=&quot;https://github.com/JohnSundell/Plot&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Plot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;enabling &lt;a href=&quot;https://github.com/JohnSundell/Splash&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Splash&lt;/a&gt; and its Swift syntax highlighting plugin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you prefer video, this &lt;a href=&quot;https://www.youtube.com/watch?v=JqdS-oi96Gk&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;tutorial by Kilo Loco&lt;/a&gt; is an excellent option.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot; tabindex=&quot;-1&quot;&gt;Getting started&lt;/h2&gt;
&lt;p&gt;If you are reading this post and wondering how to even begin using Publish to generate a site, I found &lt;a href=&quot;https://www.lahteenlahti.com/how-to-use-publish/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;this post by Perttu Lähteenlahti very helpful&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&#39;s assume you have followed Perttu&#39;s instructions, that you created a site called &lt;code&gt;SomeNewSite&lt;/code&gt;, and you are viewing the result generated by Publish:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/1-site-example-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/1-site-example-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Basic site styling as provided by the built-in Foundation theme.&quot; /&gt; 
&lt;/picture&gt;
&lt;h2 id=&quot;duplicating-the-foundation-theme&quot; tabindex=&quot;-1&quot;&gt;Duplicating the Foundation Theme&lt;/h2&gt;
&lt;p&gt;In the &lt;code&gt;SomeNewSite&lt;/code&gt; folder, open &lt;code&gt;Package.swift&lt;/code&gt; using Xcode.&lt;/p&gt;
&lt;p&gt;In Xcode, open &lt;code&gt;Sources&lt;/code&gt; → &lt;code&gt;SomeNewSite&lt;/code&gt; → &lt;code&gt;main.swift&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The following should catch your eye:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// This will generate your website using the built-in Foundation theme:
try SomeNewSite().publish(withTheme: .foundation)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Command-clicking on the &lt;code&gt;.foundation&lt;/code&gt; argument and choosing &lt;strong&gt;Jump to Definition&lt;/strong&gt; reveals that the &lt;code&gt;Theme+Foundation.swift&lt;/code&gt; file defines the Foundation theme. Progress!&lt;/p&gt;
&lt;p&gt;It is not advisable to modify the provided theme as future updates to Publish will create conflicts with any changes you make.&lt;/p&gt;
&lt;p&gt;It is better to duplicate the provided theme. You can then use the duplicate as a starting point for defining the content and presentation of your website.&lt;/p&gt;
&lt;p&gt;Before leaving the &lt;code&gt;Theme+Foundation.swift&lt;/code&gt; file, highlight and copy all its code to your clipboard: &lt;strong&gt;Command-A&lt;/strong&gt; and then &lt;strong&gt;Command-C&lt;/strong&gt; will do the trick.&lt;/p&gt;
&lt;p&gt;Say your new theme will be named &lt;em&gt;Basic&lt;/em&gt;. Create a file named &lt;code&gt;Theme+Basic.swift&lt;/code&gt; in the &lt;code&gt;Sources&lt;/code&gt; → &lt;code&gt;SomeNewSite&lt;/code&gt; folder:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/2-new-file-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/2-new-file-light.png&quot; loading=&quot;lazy&quot; alt=&quot;The newly created Theme+Basic.swift inside the Sources → SomeNewSite folder.&quot; style=&quot;width: 39%;&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Place your cursor in that newly created file and replace the existing code: &lt;strong&gt;Command-A&lt;/strong&gt; then &lt;strong&gt;Command-V&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;At this point you may wish to update the comment at the top of the &lt;code&gt;Theme+Basic.swift&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;//
//  Theme+Basic.swift
//
//
//  Created by Your Name on 2020-08-13.
//
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is now necessary to import a couple of additional packages.&lt;/p&gt;
&lt;p&gt;Above the &lt;code&gt;import Plot&lt;/code&gt; statement, add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import Foundation
import Publish
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Theme&lt;/code&gt; extension tells Publish where to find the stylesheet that will control the presentation of content. Make edits so that the &lt;code&gt;Theme&lt;/code&gt; extension is defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Theme where Site == SomeNewSite {
    /// My customized &amp;quot;Basic&amp;quot; theme.
    static var basic: Self {
        Theme(
            htmlFactory: BasicHTMLFactory(),
            resourcePaths: [&amp;quot;Resources/BasicTheme/styles.css&amp;quot;]
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, where the &lt;code&gt;FoundationHTMLFactory&lt;/code&gt; struct is defined:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;private struct FoundationHTMLFactory&amp;lt;Site: Website&amp;gt;: HTMLFactory {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... make edits such that the code reads as follows, instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;private struct BasicHTMLFactory: HTMLFactory {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you now switch to the Terminal application, and type &lt;code&gt;publish run&lt;/code&gt; in the &lt;code&gt;SomeNewSite&lt;/code&gt; folder, the compiler will throw many errors. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;error: reference to invalid associated type &#39;Site&#39; of type &#39;BasicHTMLFactory&#39;
    func makeSectionHTML(for section: Section&amp;lt;Site&amp;gt;,
                                              ^
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By switching to Xcode, command-clicking on the &lt;code&gt;Site&lt;/code&gt; type (line 23, for example), and choosing &lt;strong&gt;Jump to Definition&lt;/strong&gt;, you will see:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public protocol HTMLFactory {
    /// The website that the factory is for. Generic constraints may be
    /// applied to this type to require that a website fulfills certain
    /// requirements in order to use this factory.
    associatedtype Site: Website

    ...
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;main.swift&lt;/code&gt; a struct named &lt;code&gt;SomeNewSite&lt;/code&gt; that conforms to the protocol &lt;code&gt;Website&lt;/code&gt; is defined.&lt;/p&gt;
&lt;p&gt;And there is the solution&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; – in &lt;code&gt;Theme+Basic.swift&lt;/code&gt; all references to the &lt;code&gt;Site&lt;/code&gt; type parameter in the &lt;code&gt;BasicHTMLFactory&lt;/code&gt; struct must be replaced with references to the &lt;code&gt;SomeNewSite&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;Do this now in Xcode. Be sure to use a case-sensitive find and replace operation, but be careful not to acccidentially replace the &lt;code&gt;Site&lt;/code&gt; text in the extension of the &lt;code&gt;Theme&lt;/code&gt; type (probably on or around line 12).&lt;/p&gt;
&lt;p&gt;You are almost done! 😅&lt;/p&gt;
&lt;p&gt;Return to &lt;code&gt;main.swift&lt;/code&gt;. Tell the compiler to build your site using the new theme. Update the final two lines of code to read:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Generate the website using my customized Basic theme
try SomeNewSite().publish(withTheme: .basic)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Switch to the Terminal application. Type &lt;code&gt;publish run&lt;/code&gt; in the &lt;code&gt;SomeNewSite&lt;/code&gt; folder. The Swift code will now compile, but the site will not generate, because Publish cannot find the stylesheet:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;Fatal error: Error raised at top level: Publish encountered an error:
[step] Generate HTML
[path] Resources/BasicTheme/styles.css
[info] Failed to copy theme resource
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;To correct this, in your &lt;code&gt;Resources&lt;/code&gt; folder, create a new folder named &lt;code&gt;BasicTheme&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Inside that folder, create a new file named &lt;code&gt;styles.css&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Expand the &lt;code&gt;Publish&lt;/code&gt; package in Xcode, then navigate to the &lt;code&gt;Resources&lt;/code&gt; → &lt;code&gt;FoundationTheme&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;From the &lt;code&gt;FoundationTheme&lt;/code&gt; folder, copy and paste the entire conents of the &lt;code&gt;styles.css&lt;/code&gt; file into your newly created CSS file in the &lt;code&gt;BasicTheme&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Here is what things should generally look like at this point:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/3-new-stylesheet-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/3-new-stylesheet-light.png&quot; loading=&quot;lazy&quot; alt=&quot;The newly created Theme+Basic.swift inside the Sources → SomeNewSite folder.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;You may now wish to update the comment at the top of your new stylesheet file.&lt;/p&gt;
&lt;p&gt;Switch back to the Terminal application. Type &lt;code&gt;publish run&lt;/code&gt; in the &lt;code&gt;SomeNewSite&lt;/code&gt; folder.  This time the site should generate successfully.&lt;/p&gt;
&lt;p&gt;If you load the site, you should once again see the following:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/1-site-example-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/1-site-example-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Basic site styling as provided by the built-in Foundation theme.&quot; /&gt; 
&lt;/picture&gt; 
&lt;p&gt;It is perhaps a bit deflating to do all that work to get the same result, but now the site is being generated by your own custom theme. It gets easier from here!&lt;/p&gt;
&lt;h2 id=&quot;adjusting-presentation-using-css&quot; tabindex=&quot;-1&quot;&gt;Adjusting Presentation Using CSS&lt;/h2&gt;
&lt;p&gt;Now that the &lt;em&gt;Basic&lt;/em&gt; theme is set up, adjusting the presentation of site content using CSS is straightforward.&lt;/p&gt;
&lt;p&gt;Test that this is working by adjusting the background color in &lt;code&gt;styles.css&lt;/code&gt; inside the &lt;code&gt;BasicTheme&lt;/code&gt; folder to display in orange:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;body {
    background: orange;
    color: hsl(0,0%,0%);
    font-family: Helvetica, Arial;
    text-align: center;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that if your computer is running in dark mode, you&#39;d need to change this section of the &lt;code&gt;styles.css&lt;/code&gt; file instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@media (prefers-color-scheme: dark) {
    body {
        background-color: orange;
    }
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whenever you make an edit to the stylesheet, the website must be rebuilt. In the &lt;code&gt;SomeNewSite&lt;/code&gt; folder, type &lt;code&gt;publish run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now reload the page in your web browser.&lt;/p&gt;
&lt;p&gt;You should see that the background of the page is now bright orange.&lt;/p&gt;
&lt;p&gt;Beware: browsers will, whenever possible, load files from a cache rather than from the server. Since you are trying to test a change to your stylesheet, it&#39;s important that you are not reloading from a cache of the original stylesheet.&lt;/p&gt;
&lt;p&gt;In Safari, &lt;strong&gt;Option-Command-R&lt;/strong&gt; triggers the &lt;strong&gt;Reload Page from Origin&lt;/strong&gt; command, which should ignore any cached files and instead, as suggested by the name, reload files from the server. In Chrome, I believe the equivalent command is &lt;strong&gt;Shift-Command-R&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;It is helpful to enable the &lt;strong&gt;Develop&lt;/strong&gt; menu in Safari. To do this, open Safari Preferences, and on the Advanced tab, enable the &lt;strong&gt;Show Develop menu in menu bar&lt;/strong&gt; option.&lt;/p&gt;
&lt;p&gt;From the &lt;strong&gt;Develop&lt;/strong&gt; menu, &lt;strong&gt;Option-Command-E&lt;/strong&gt; to trigger the &lt;strong&gt;Empty Caches&lt;/strong&gt; command can be useful.&lt;/p&gt;
&lt;p&gt;For further reading, if you are new to web development, &lt;a href=&quot;https://www.lifewire.com/get-inspect-element-tool-for-browser-756549&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;learning how to inspect web page elements&lt;/a&gt; is recommended. This &lt;a href=&quot;https://ryanstutorials.net/css-tutorial/css-selectors.php&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;tutorial on CSS selectors&lt;/a&gt; may also be helpful.&lt;/p&gt;
&lt;p&gt;If you&#39;ve made a change to a CSS file, but do not see it reflected on your page, do not worry. This happened to me &lt;em&gt;dozens&lt;/em&gt; of times. Ask yourself these questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Did I save changes to the CSS file?&lt;/li&gt;
&lt;li&gt;Did I remember to issue the &lt;code&gt;publish run&lt;/code&gt; command to regenerate the website?&lt;/li&gt;
&lt;li&gt;Did I reload the page ignoring cached files? (see keyboard shortcuts above)&lt;/li&gt;
&lt;li&gt;Have I emptied the browser cache? (see keyboard shortcut above)&lt;/li&gt;
&lt;li&gt;Am I using the correct CSS selectors to target an element? (see suggested further reading above)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;modifying-content-using-plot&quot; tabindex=&quot;-1&quot;&gt;Modifying Content Using Plot&lt;/h2&gt;
&lt;p&gt;Plot defines a domain-specific language (DSL) for writing HTML in Publish. This means you can safely write HTML using Swift. It&#39;s worth &lt;a href=&quot;https://github.com/JohnSundell/Plot&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;reading the documentation&lt;/a&gt; – it is extensive and well written.&lt;/p&gt;
&lt;p&gt;Let&#39;s review a quick example here. Say that you wish to add the date of a published article to the item list on the main page, so that the page will look like this&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/4-date-example-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/4-date-example-light.png&quot; loading=&quot;lazy&quot; alt=&quot;The date of the article is now included below a link to the article.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;Open the &lt;code&gt;Theme+Basic.swift&lt;/code&gt; file in Xcode, and navigate to the &lt;code&gt;itemList&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;Add a call to the &lt;code&gt;h2&lt;/code&gt; method just below where the &lt;code&gt;h1&lt;/code&gt; method is invoked:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;static func itemList&amp;lt;T: Website&amp;gt;(for items: [Item&amp;lt;T&amp;gt;], on site: T) -&amp;gt; Node {
	return .ul(
		.class(&amp;quot;item-list&amp;quot;),
		.forEach(items) { item in
			.li(.article(
				.h1(.a(
					.href(item.path),
					.text(item.title)
				)),
				.h2(.text(&amp;quot;Published on: &#92;(item.date)&amp;quot;)),
				.tagList(for: item, on: site),
				.p(.text(item.description))
			))
		}
	)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That new code retrieves the date of the current item and positions it just below a link to the item.&lt;/p&gt;
&lt;p&gt;If you regenerate the site using the &lt;code&gt;publish run&lt;/code&gt; command, and reload it in your browser, you should see something like this:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/5-date-unformatted-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/5-date-unformatted-light.png&quot; loading=&quot;lazy&quot; alt=&quot;The date of the article is  included but not formatted.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;The date is not nicely formatted.&lt;/p&gt;
&lt;p&gt;The wonderful part of building a website using Swift is that you can apply all your existing knowledge to the endeavour.&lt;/p&gt;
&lt;p&gt;Add a quick extension to the &lt;code&gt;Date&lt;/code&gt; type at the top of &lt;code&gt;Theme+Basic.swift&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension Date {
    var asText: String {
        let formatter = DateFormatter()
        formatter.dateFormat = &amp;quot;dd MMMM, yyyy&amp;quot;
        let dateString = formatter.string(from: self)
        return dateString
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... and a slight change to the &lt;code&gt;itemList&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.h2(.text(&amp;quot;Published on: &#92;(item.date.asText)&amp;quot;)),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... and you should find that the date is now better formatted.&lt;/p&gt;
&lt;p&gt;I often forget the rules for formatting dates in Swift; &lt;a href=&quot;https://www.datetimeformatter.com/how-to-format-date-time-in-swift/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;this site is a useful reference&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To learn more about how to build site content using the Plot DSL, do have a look at &lt;a href=&quot;https://www.youtube.com/watch?v=JqdS-oi96Gk&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Kilo Loco&#39;s video&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To see the complete list of HTML elements that the Plot DSL API supports, &lt;a href=&quot;https://github.com/JohnSundell/Plot/blob/master/Sources/Plot/API/HTMLElements.swift&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;this page is helpful&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remember, Plot is extensible – you can &lt;a href=&quot;https://github.com/JohnSundell/Plot#defining-custom-components&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;define your own components&lt;/a&gt;, and more.&lt;/p&gt;
&lt;h2 id=&quot;enabling-splash-for-swift-syntax-highlighting&quot; tabindex=&quot;-1&quot;&gt;Enabling Splash for Swift Syntax Highlighting&lt;/h2&gt;
&lt;p&gt;Being able to share nicely highlighted excerpts of Swift code on this website was the motivating factor for my own move to using the Publish static site generator.&lt;/p&gt;
&lt;p&gt;To get started, per &lt;a href=&quot;https://github.com/JohnSundell/SplashPublishPlugin#installation&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;John Sundell&#39;s instructions&lt;/a&gt;, modify &lt;code&gt;Package.swift&lt;/code&gt; to read as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// swift-tools-version:5.2

import PackageDescription

let package = Package(
    name: &amp;quot;SomeNewSite&amp;quot;,
    products: [
        .executable(
            name: &amp;quot;SomeNewSite&amp;quot;,
            targets: [&amp;quot;SomeNewSite&amp;quot;]
        )
    ],
    dependencies: [
        .package(name: &amp;quot;Publish&amp;quot;, url: &amp;quot;https://github.com/johnsundell/publish.git&amp;quot;, from: &amp;quot;0.6.0&amp;quot;),
        .package(name: &amp;quot;SplashPublishPlugin&amp;quot;, url: &amp;quot;https://github.com/johnsundell/splashpublishplugin&amp;quot;, from: &amp;quot;0.1.0&amp;quot;)
    ],
    targets: [
        .target(
            name: &amp;quot;SomeNewSite&amp;quot;,
            dependencies: [&amp;quot;Publish&amp;quot;, &amp;quot;SplashPublishPlugin&amp;quot;]
        )
    ]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, changes to &lt;code&gt;main.swift&lt;/code&gt; are required.&lt;/p&gt;
&lt;p&gt;Add this line to the end of the list of import statements:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import SplashPublishPlugin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modifications to the final line of code are required. Your site is currently being generated with the default pipeline provided by Publish:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Generate the website using my customized Basic theme
try SomeNewSite().publish(withTheme: .basic)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use Splash, a customized pipeline for website generation is required.&lt;/p&gt;
&lt;p&gt;Modify the code to read as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;try SomeNewSite().publish(using: [
  .copyResources(),
  .installPlugin(.splash(withClassPrefix: &amp;quot;&amp;quot;)),
  .addMarkdownFiles(),
  .sortItems(by: &#92;.date, order: .descending),
  .generateHTML(withTheme: .basic),
  .unwrap(RSSFeedConfiguration.default) { config in
      .generateRSSFeed(
        including: [.posts],
          config: config
      )
  },
  .generateSiteMap()
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That custom publishing pipeline mimics the default pipeline, but includes Splash.&lt;/p&gt;
&lt;p&gt;Now, navigate to the &lt;code&gt;Content&lt;/code&gt; → &lt;code&gt;posts&lt;/code&gt; folder in Xcode.&lt;/p&gt;
&lt;p&gt;Modify &lt;code&gt;first-post.md&lt;/code&gt;, below the metadata section, to read as follows:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;# My first post

My first post&#39;s text.

```
var i = 10
while i &gt; 0 {
    print(&quot;&#92;(i)...&quot;)
    i -= 1
}
print(&quot;Blast off!&quot;)
```&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Now invoke &lt;code&gt;publish run&lt;/code&gt; to regenerate your site. From the main page, follow the link to read the post.&lt;/p&gt;
&lt;p&gt;You might be disappointed to see that the Swift code is not syntax-highlighted.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.lifewire.com/get-inspect-element-tool-for-browser-756549&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Inspect an element&lt;/a&gt; near the start of the Swift code block.&lt;/p&gt;
&lt;p&gt;You should see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;amp;lt;span class=&amp;quot;keyword&amp;quot;&amp;amp;gt;var&amp;amp;lt;/span&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, what&#39;s happening is that Splash wraps Swift code in &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tags that specify certain CSS classes.&lt;/p&gt;
&lt;p&gt;To see color-highlighted code, CSS is required.&lt;/p&gt;
&lt;p&gt;Just below is CSS that will &lt;a href=&quot;https://github.com/JohnSundell/Splash/blob/master/Examples/sundellsColors.css&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;provide colors according to John Sundell&#39;s theme&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Copy and paste this at the bottom of your &lt;code&gt;styles.css&lt;/code&gt; file in the &lt;code&gt;BasicTheme&lt;/code&gt; folder&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:4&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;pre code {
    color: hsl(180,12%,70%);
}

.preprocessing {
    color: hsl(45,100%,36%);
}

.comment {
    color: hsl(195,16%,50%);
}

.number {
    color: hsl(11,65%,60%);
}

.call {
    color: hsl(209,77%,55%);
}

.property {
    color: hsl(174,68%,40%);
}

.keyword {
    color: hsl(331,79%,57%);
}

.dotAccess {
    color: hsl(71,100%,35%);
}

.type {
    color: hsl(241,41%,65%);
}

.string {
    color: hsl(19,96%,55%);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Regenerate your site, and reload the post. You should now see that the Swift code is syntax-highlighted with color.&lt;/p&gt;
&lt;p&gt;You can customize the colors as desired, of course.&lt;/p&gt;
&lt;p&gt;If you are looking to mimic colors from existing themes, I think you will find the &lt;a href=&quot;https://apps.apple.com/us/app/classic-color-meter/id451640037?mt=12&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Classic Color Meter&lt;/a&gt; app to be very useful. I purchased Classic Color Meter and used it extensively while developing this site&#39;s look and feel.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://paletton.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Paletton&lt;/a&gt; site is also excellent.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Whew! 😅&lt;/p&gt;
&lt;p&gt;I hope this article has helped you blast off with Publish. 🚀&lt;/p&gt;
&lt;p&gt;Please let me know how this goes for you.&lt;/p&gt;
&lt;p&gt;I&#39;d love to keep this article current, so if something doesn&#39;t work for you, please &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Good luck!&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;This may not be the &lt;em&gt;most correct&lt;/em&gt; solution; &lt;a href=&quot;mailto:contact@russellgordon.ca&quot;&gt;I welcome suggestions&lt;/a&gt; for a better approach.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;I&#39;ve removed the orange background from the last section of this tutorial.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:2&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;On Friday, August 14, 2020, the destination for this link was updated to point to a stylesheet designed specifically for presenting code with Splash, as opposed to linking to an Xcode theme with John Sundell&#39;s colors.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:3&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;On March 29, 2024, CSS color codes in hexadecimal were converted to their HSL equivalents.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:4&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/creating-a-custom-theme-using-publish/" />
        </entry>
    
    
        <entry>
            <title>
                Core Data and Xcode Previews
                
            </title>
            <updated>2021-07-18T22:30:32.000Z</updated>
            <id>https://russellgordon.dev//tutorials/core-data-and-xcode-previews/</id>
            <content type="html">
                &lt;p&gt;Right now I am reading through &lt;a href=&quot;https://practicalcoredata.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Practical Core Data&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/donnywals&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Donny Wals&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Reading that book has been a welcome consolidation of my understanding of Core Data.&lt;/p&gt;
&lt;p&gt;My first exposure to the Core Data framework &lt;a href=&quot;https://russellgordon.dev/tutorials/getting-to-know-core-data/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;was  rough&lt;/a&gt;, entirely due to my own predisposition to biting off more than I can chew.&lt;/p&gt;
&lt;p&gt;When last using Core Data, I was at first disappointed because I did not understand how to provide sample data to views rendered in Xcode Previews. The ability to rapidly iterate design ideas for a view in Xcode Previews is one of my favourite aspects of programming with the SwiftUI framework.&lt;/p&gt;
&lt;p&gt;I was delighted when I eventually cobbled together some understanding of how to use Xcode Previews while obtaining sample data through a Core Data store. My intent is to clearly describe how to do just that in this article.&lt;/p&gt;
&lt;h2 id=&quot;starting-point&quot; tabindex=&quot;-1&quot;&gt;Starting Point&lt;/h2&gt;
&lt;p&gt;This &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/CoreDataAndXcodePreviews-Starter.zip&quot;&gt;Xcode project uses a basic Core Data model&lt;/a&gt; without support for working with views in Xcode Previews.&lt;/p&gt;
&lt;p&gt;It was created using &lt;a href=&quot;https://developer.apple.com/services-account/download?path=/Developer_Tools/Xcode_12.5.1/Xcode_12.5.1.xip&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Xcode 12.5.1&lt;/a&gt; – download the project to follow along, and if necessary, that version of Xcode.&lt;/p&gt;
&lt;p&gt;The finished project, including the code necessary to drive Xcode Previews, is included at the end of this article.&lt;/p&gt;
&lt;p&gt;In the project you will find an app that I built by, for the most part, following the instructions provided in Chapter 1 of &lt;a href=&quot;https://practicalcoredata.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Practical Core Data&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The app is very basic, allowing a user to add a movie to a list of movies, navigate to a detail view, and then edit the name of that movie:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/app-screenshots-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/app-screenshots-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Three app screenshots showing, in order: a list of movies, a detail screen for a movie, and an editing sheet for that same movie.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;I will not go into detail here about how the app and the &lt;code&gt;StorageProvider&lt;/code&gt; class works other than to say that I think it is a pretty fair example of how to separate the data layer from the view layer of an app. Hopefully the provided comments are clear.&lt;/p&gt;
&lt;p&gt;If you examine any of the views in the app, you will see that the Xcode Previews code is commented out.&lt;/p&gt;
&lt;p&gt;Let&#39;s start correcting that by completing the first of three steps.&lt;/p&gt;
&lt;h2 id=&quot;using-core-data-storage-in-memory&quot; tabindex=&quot;-1&quot;&gt;Using Core Data Storage In-memory&lt;/h2&gt;
&lt;p&gt;Core Data&#39;s underlying storage, by default, persists changes made. If it didn&#39;t, it would not be a very useful framework!&lt;/p&gt;
&lt;p&gt;We could drive Xcode Previews with sample data from Core Data, but if we allowed the changes to persist, every time we reload a view in a preview, more data would be added to our Core Data store.&lt;/p&gt;
&lt;p&gt;This is generally not ideal, since an Xcode Preview will be reloaded many times.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;StorageProvider.swift&lt;/code&gt; and navigate to the initializer on or around line 20:&lt;/p&gt;
&lt;p&gt;Modify the list of parameters for the initializer to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;init(inMemory: Bool = false) {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By providing a default value for the newly introduced parameter, existing call sites do not need to be updated. A default value of &lt;code&gt;false&lt;/code&gt; is logical as when the app is running outside of a preview, we want changes to the Core Data store to persist.&lt;/p&gt;
&lt;p&gt;Note that the first thing that occurs within the initializer is that an &lt;code&gt;NSPersistentContainer&lt;/code&gt; instance is created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Access the model file
persistentContainer = NSPersistentContainer(name: &amp;quot;PracticalCoreData&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Immediately after that line of code, add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Don&#39;t save information for future use if running in memory...
if inMemory {
	persistentContainer.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: &amp;quot;/dev/null&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The edits we have made here will allow us to create an instance of &lt;code&gt;StorageProvider&lt;/code&gt; whose data, when changes are made, are not persisted because they are kept in-memory only, as opposed to being written to a long-term storage medium.&lt;/p&gt;
&lt;p&gt;On to the second step...&lt;/p&gt;
&lt;h2 id=&quot;generating-sample-data&quot; tabindex=&quot;-1&quot;&gt;Generating Sample Data&lt;/h2&gt;
&lt;p&gt;The second property of the &lt;code&gt;StorageProvider&lt;/code&gt; class is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// For initializing the Core Data stack and loading the Core Data model file
let persistentContainer: NSPersistentContainer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Immediately below that property, add the following closure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// For use with Xcode Previews, provides some data to work with for examples
static var preview: StorageProvider = {
	
	// Create an instance of the provider that runs in memory only
	let storageProvider = StorageProvider(inMemory: true)
	
	// Add a few test movies
	let titles = [
				&amp;quot;The Godfather&amp;quot;,
				&amp;quot;The Shawshank Redemption&amp;quot;, 
				&amp;quot;Schindler&#39;s List&amp;quot;, 
				&amp;quot;Raging Bull&amp;quot;, 
				&amp;quot;Casablanca&amp;quot;, 
				&amp;quot;Citizen Kane&amp;quot;,
				]
				
	for title in titles {
		storageProvider.saveMovie(named: title)
	}
	
	// Now save these movies in the Core Data store
	do {
		try storageProvider.persistentContainer.viewContext.save()
	} catch {
		// Something went wrong 😭
		print(&amp;quot;Failed to save test movies: &#92;(error)&amp;quot;)
	}

	return storageProvider
}()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The third step will be completed a bit later on.&lt;/p&gt;
&lt;p&gt;At this point, we are ready to try things out with the Xcode Preview for &lt;code&gt;MovieListView&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Navigate to &lt;code&gt;MovieListView.swift&lt;/code&gt; and scroll to the bottom of the file.&lt;/p&gt;
&lt;p&gt;Uncomment the structure for Xcode Previews, then add the following modifier to the &lt;code&gt;NavigationView&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.environmentObject(StorageProvider.preview)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The entire structure should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct MovieListView_Previews: PreviewProvider {

    static var previews: some View {

        NavigationView {
            MovieListView()
        }
        .environmentObject(StorageProvider.preview)
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The static &lt;code&gt;preview&lt;/code&gt; property on the &lt;code&gt;StorageProvider&lt;/code&gt; class returns an instance of &lt;code&gt;StorageProvider&lt;/code&gt; itself, and that instance is then inserted into the environment – which in turn is accessed by the &lt;code&gt;MovieListView&lt;/code&gt; structure when the Xcode Preview runs.&lt;/p&gt;
&lt;p&gt;Now start a Live Preview inside the Xcode Previews panel.&lt;/p&gt;
&lt;p&gt;You should be able to navigate around the three views of the app, and work with the provided data.&lt;/p&gt;
&lt;p&gt;Before continuing, let&#39;s explore what happens if we &lt;em&gt;do not&lt;/em&gt; load the Core Data store in-memory only.&lt;/p&gt;
&lt;p&gt;Return to &lt;code&gt;StorageProvider.swift&lt;/code&gt; and, on or around line 24, modify the code such that &lt;code&gt;false&lt;/code&gt; is passed as the argument for the &lt;code&gt;inMemory&lt;/code&gt; parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Create an instance of the provider that runs in memory only
let storageProvider = StorageProvider(inMemory: false)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now try running and re-running the Live View of &lt;code&gt;MovieListView&lt;/code&gt; once or twice.&lt;/p&gt;
&lt;p&gt;You will not at first see the list of movies change. Run the project in the simulator. Then, return to a Live View of &lt;code&gt;MovieListView&lt;/code&gt; in Xcode Previews.&lt;/p&gt;
&lt;p&gt;At this point, you should see that the list of movies has been repeated several times. That is because each time a Live View was run, the &lt;code&gt;preview&lt;/code&gt; closure was invoked, re-adding several movies to the list of movies in the Core Data store.&lt;/p&gt;
&lt;p&gt;I am not certain why it is necessary to run the app in the simulator to see the result of re-running the &lt;code&gt;preview&lt;/code&gt; closure several times. I am not at all familiar with the underpinnings of how Xcode works.&lt;/p&gt;
&lt;p&gt;Nonetheless, this behaviour is probably not what you want in the long term – so revert the code around line 24 of &lt;code&gt;StorageProvider&lt;/code&gt; such that the Core Data store runs in-memory again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Create an instance of the provider that runs in memory only
let storageProvider = StorageProvider(inMemory: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Close Xcode entirely, then open the project again.&lt;/p&gt;
&lt;p&gt;When you run Xcode Previews, you should see just the initial list of movies on &lt;code&gt;MovieListView&lt;/code&gt;, with no repeats.&lt;/p&gt;
&lt;h2 id=&quot;providing-a-single-instance-of-a-movie&quot; tabindex=&quot;-1&quot;&gt;Providing a Single Instance of a Movie&lt;/h2&gt;
&lt;p&gt;This is the third and final step of the tutorial.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Movie&lt;/code&gt; class is connected to the &lt;code&gt;Movie&lt;/code&gt; entity I defined in the Core Data model editor.&lt;/p&gt;
&lt;p&gt;Here we are going to extend this class so that a static property provides a single movie that we can use to drive &lt;code&gt;MovieDetailView&lt;/code&gt; and &lt;code&gt;MovieEditView&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;Model&lt;/code&gt; group of the Xcode project, create a new file named &lt;code&gt;Movie+PreviewProvider.swift&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add the following code to the new file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import CoreData
import Foundation

// Exists to provide a movie to use with MovieDetailView and MovieEditView
extension Movie {
    
    // Example movie for Xcode previews
    static var example: Movie {
        
        // Get the first movie from the in-memory Core Data store
        let context = StorageProvider.preview.persistentContainer.viewContext
        
        let fetchRequest: NSFetchRequest&amp;lt;Movie&amp;gt; = Movie.fetchRequest()
        fetchRequest.fetchLimit = 1
        
        let results = try? context.fetch(fetchRequest)
        
        return (results?.first!)!
    }
    
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The optionals that are being force-unwrapped on the last line of that static computed property may give you pause.&lt;/p&gt;
&lt;p&gt;Let&#39;s edit &lt;code&gt;MovieDetailView.swift&lt;/code&gt; and then re-visit the code above.&lt;/p&gt;
&lt;p&gt;Uncomment the structure for Xcode Previews, then again add the following modifier to the &lt;code&gt;NavigationView&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.environmentObject(StorageProvider.preview)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, for the &lt;code&gt;movie&lt;/code&gt; parameter on &lt;code&gt;MovieDetailView&lt;/code&gt;, provide &lt;code&gt;Movie.example&lt;/code&gt; as the argument.&lt;/p&gt;
&lt;p&gt;The entire structure should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct MovieDetailView_Previews: PreviewProvider {
    
    static var previews: some View {
        NavigationView {
            MovieDetailView(movie: Movie.example)
        }
        .environmentObject(StorageProvider.preview)
    }
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the Xcode Preview is loaded, our sample data is loaded via the &lt;code&gt;preview&lt;/code&gt; static property on &lt;code&gt;StorageProvider&lt;/code&gt; and again, inserted into the environment.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;MovieDetailView&lt;/code&gt; loads, from the &lt;code&gt;Movie&lt;/code&gt; extension above, we pass the static computed property &lt;code&gt;example&lt;/code&gt; as the argument for the movie whose details will be shown.&lt;/p&gt;
&lt;p&gt;Since the sample data is loaded first, in &lt;code&gt;StorageProvider&lt;/code&gt;, we can safely force-unwrap the result of the fetch request in our extension to the &lt;code&gt;Movie&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;You should now be able to see &lt;code&gt;MovieDetailView&lt;/code&gt; in the Xcode Previews panel.&lt;/p&gt;
&lt;p&gt;In much the same way, make edits to the preview structure for &lt;code&gt;MovieEditView&lt;/code&gt;, such that the structure looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct MovieEditView_Previews: PreviewProvider {
    
    static var previews: some View {
        NavigationView {
            MovieEditView(dismissView: .constant(false),
                          movie: Movie.example)
        }
        .environmentObject(StorageProvider.preview)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Going forward, when a new entity is added to the Core Data model, two steps need to occur:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;preview&lt;/code&gt; property of &lt;code&gt;StorageProvider&lt;/code&gt;, appropriate sample data must be created and added to the Core Data store.&lt;/li&gt;
&lt;li&gt;Write an extension to the class for the newly defined entity, and create a static computed property named &lt;code&gt;example&lt;/code&gt; that loads a record from that entity.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here is &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/CoreDataAndXcodePreviews-Completed.zip&quot;&gt;a completed version of this project&lt;/a&gt;, with all edits described above.&lt;/p&gt;
&lt;p&gt;If you have found any errors in this article, or if this article has been useful to you, &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;please let me know&lt;/a&gt;. 😀&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/core-data-and-xcode-previews/" />
        </entry>
    
    
        <entry>
            <title>
                Changing the Name of an App
                
            </title>
            <updated>2020-09-20T15:20:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/changing-the-name-of-an-app/</id>
            <content type="html">
                &lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/lptezHr7rqA&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; allowfullscreen=&quot;&quot; title=&quot;Changing the Name of an App&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;It&#39;s common to want to change the name of your app, as it will be seen by users, long after you selected the name of the project when you &lt;a href=&quot;https://russellgordon.dev/tutorials/creating-a-new-xcode-project-for-a-swiftui-app&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;first created it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s best to keep an app&#39;s name brief, otherwise the name will be truncated below the app icon on the device.&lt;/p&gt;
&lt;p&gt;For example, right now, you can see the name of the application I&#39;m working with doesn&#39;t fit on a device with a smaller screen size.&lt;/p&gt;
&lt;p&gt;First, select the blue project file in the top left corner of the Project navigator in Xcode. You can open the Project navigator using the keyboard shortcut &lt;strong&gt;Command-1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Select the &lt;strong&gt;General&lt;/strong&gt; tab.&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;Display Name&lt;/strong&gt; field, type the new name for the app.&lt;/p&gt;
&lt;p&gt;Next, select the &lt;strong&gt;Build Settings&lt;/strong&gt; tab, then search for &lt;em&gt;Product Name&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ll double-click on the right, and change this value to the new name as well.&lt;/p&gt;
&lt;p&gt;Now build your program.&lt;/p&gt;
&lt;p&gt;When it has been installed on the device, you will see that it has the newly specified name.&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/changing-the-name-of-an-app/" />
        </entry>
    
    
        <entry>
            <title>
                Building an Animated Progress Meter View With SwiftUI
                
            </title>
            <updated>2020-08-17T19:15:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/building-an-animated-progress-meter-view-with-swiftui/</id>
            <content type="html">
                &lt;p&gt;When it comes to SwiftUI, I am but a pup, wet behind the ears.&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, I encourage my own students to explain their work to others either in writing or with a video. If you can clearly communicate an idea to others using correct vocabulary  then you really understand it. So it is in that spirit that I share this article on how to build a composable progress meter view – the first time I&#39;ve built something in SwiftUI that I feel might be useful to others.&lt;/p&gt;
&lt;p&gt;If you are an experienced SwiftUI developer and have feedback about what I&#39;ve written – &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;I welcome it&lt;/a&gt;! I am very much responsible for any errors or inaccuracies.&lt;/p&gt;
&lt;h2 id=&quot;goals&quot; tabindex=&quot;-1&quot;&gt;Goals&lt;/h2&gt;
&lt;p&gt;After reading this article, you should have an understanding of how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;combine &lt;code&gt;HStack&lt;/code&gt;, &lt;code&gt;VStack&lt;/code&gt;, and &lt;code&gt;ZStack&lt;/code&gt; views&lt;/li&gt;
&lt;li&gt;use animations to highlight a transition between view states&lt;/li&gt;
&lt;li&gt;use a &lt;code&gt;GeometryReader&lt;/code&gt; container view to ensure the progress meter adapts to varying screen sizes&lt;/li&gt;
&lt;li&gt;apply the hue-saturation-brightness model to represent colors&lt;/li&gt;
&lt;li&gt;build a lightweight, composable view that accepts parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is what the finished progress meter looks like – in this case, embedded within a multiplication practice app:&lt;/p&gt;
&lt;figure style=&quot;width: 436px;&quot;&gt;
	&lt;video width=&quot;436&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/example.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Showing progress toward a goal&lt;/h4&gt;
		&lt;p&gt;Note that the progress meter view adapts to different device sizes.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Feel free to pause and come back to the tutorial as you complete each logical section. This is a somewhat lengthy article. Let&#39;s begin!&lt;/p&gt;
&lt;h2 id=&quot;arranging-the-views&quot; tabindex=&quot;-1&quot;&gt;Arranging the Views&lt;/h2&gt;
&lt;p&gt;Begin by &lt;a href=&quot;https://russellgordon.dev/tutorials/creating-a-new-xcode-project-for-a-swiftui-app&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;creating a new iOS App&lt;/a&gt; named &lt;strong&gt;ProgressMeter&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: If you are using Xcode 11, whenever a property of the &lt;code&gt;ContentView&lt;/code&gt; structure is referenced below in this tutorial, you must insert &lt;code&gt;self.&lt;/code&gt; prior to the property name. This is not required in Xcode 12.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In &lt;code&gt;ContentView.swift&lt;/code&gt; you should see something like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;import SwiftUI

struct ContentView: View {
    var body: some View {
        Text(&amp;quot;Hello, world!&amp;quot;)
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s begin by defining a &lt;code&gt;Rectangle&lt;/code&gt; view that will form the first part of our progress meter.&lt;/p&gt;
&lt;p&gt;For the time being, we&#39;ll work with constant dimensions, and later, introduce &lt;code&gt;GeometryReader&lt;/code&gt; to gain a flexible layout. I like to build views against the smallest possible device. In Xcode 12, this is the &lt;strong&gt;iPod Touch (7th generation)&lt;/strong&gt;. In Xcode 11, this is the &lt;strong&gt;iPhone SE (1st generation)&lt;/strong&gt; – though you may have to &lt;a href=&quot;https://www.simpleswiftguide.com/how-to-add-missing-iphone-se-simulator-in-xcode-11-with-ios-13-sdks/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;add that simulator manually at first&lt;/a&gt;. Based on this &lt;a href=&quot;https://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;handy screen size chart&lt;/a&gt;, the maximum available height for these devices will be 548 points (that&#39;s 568 less 20 points for the toolbar). Set your &lt;a href=&quot;https://developer.apple.com/documentation/xcode/running_your_app_in_the_simulator_or_on_a_device&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;run destination&lt;/a&gt; now.&lt;/p&gt;
&lt;p&gt;Then replace the &lt;code&gt;Text&lt;/code&gt; view inside the &lt;code&gt;body&lt;/code&gt; property with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Rectangle()
	.frame(width: 100, height: 548 - 44, alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&#39;ll note the use of an expression, &lt;code&gt;548 - 44&lt;/code&gt;, as the &lt;code&gt;height&lt;/code&gt; argument. That&#39;s deliberate; we&#39;ll revisit this later on.&lt;/p&gt;
&lt;p&gt;Moving on, to create the appearance of a progress meter &amp;quot;filling up&amp;quot; we&#39;ll need another view.&lt;/p&gt;
&lt;p&gt;We&#39;re going to make another &lt;code&gt;Rectangle&lt;/code&gt; that slides up, revealing the &lt;code&gt;Rectangle&lt;/code&gt; below it.&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;View&lt;/code&gt; protocol requires that a single view is returned for the &lt;code&gt;body&lt;/code&gt; property, we&#39;ll embed both of the rectangles in a &lt;code&gt;VStack&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;VStack {
	// &amp;quot;Fill&amp;quot; for progress meter; stationary
	Rectangle()
		.frame(width: 100, height: 548 - 44, alignment: .center)
	// Will slide up
	Rectangle()
		.frame(width: 100, height: 548 - 44, alignment: .center)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, that&#39;s not what we want. At the moment the two rectangles are, as we&#39;ve described with our code, vertically stacked upon one another.&lt;/p&gt;
&lt;p&gt;To create the illusion of a filling progress meter, we need to make use of the &lt;em&gt;z&lt;/em&gt;-axis. The rectangle that slides up must be at the front, so it is listed second in the &lt;code&gt;ZStack&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Adjust the code to introduce a &lt;code&gt;ZStack&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;VStack {
	ZStack {
		// &amp;quot;Fill&amp;quot; for progress meter; stationary
		Rectangle()
			.frame(width: 100, height: 548 - 44, alignment: .center)
		// Will slide up
		Rectangle()
			.frame(width: 100, height: 548 - 44, alignment: .center)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the two rectangles sit upon one another.&lt;/p&gt;
&lt;p&gt;The second rectangle needs a different color. Rather than specifying black or white, we use the &lt;code&gt;primary&lt;/code&gt; color, so that the view works on a device in both light and dark modes. By inverting that color, we get the opposite:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Will slide up
Rectangle()
	.fill(Color.primary)
	.colorInvert()
	.frame(width: 100, height: 548 - 44, alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the fill of the rectangle that will slide up matches the background.&lt;/p&gt;
&lt;p&gt;At this point, it appears as though no views are present at all!&lt;/p&gt;
&lt;p&gt;However, if you place your cursor in Xcode on the line of code that defines either of the &lt;code&gt;Rectangle&lt;/code&gt; views, you&#39;ll see a faint blue outline showing you where the view is:&lt;/p&gt;
&lt;figure style=&quot;width: 33%;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/obscured-view.png&quot; loading=&quot;lazy&quot; alt=&quot;The rectangle that will slide up completely overlaps the rectangle that represents the progress meter fill.&quot; style=&quot;width: 33%;&quot; /&gt; 
&lt;/figure&gt;
&lt;p&gt;The &lt;em&gt;offset&lt;/em&gt; view modifier allows us to &amp;quot;[o]ffset [a] view by the horizontal and vertical amount specified in the offset parameter.&amp;quot;&lt;/p&gt;
&lt;p&gt;Add the following modifier to the second rectangle – the view that will slide up:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.offset(CGSize(width: 0, height: -1 * (548 - 44)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;em&gt;immediately&lt;/em&gt; places the rectangle that will slide up vertically above the rectangle that will represent the fill of the progress meter. You should see only a black rectangle.&lt;/p&gt;
&lt;p&gt;Not what we want, right? It&#39;s time to consider the &lt;em&gt;state&lt;/em&gt; of our view. As you&#39;ve heard often while learning SwiftUI, &lt;em&gt;views are a function of state&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Where do we want the rectangle that will slide up to &lt;em&gt;begin&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Directly on top of the rectangle behind it.&lt;/p&gt;
&lt;p&gt;Where do we want the rectangle that will slide up to &lt;em&gt;finish&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Positioned vertically above the rectangle behind it.&lt;/p&gt;
&lt;p&gt;We need to create &lt;em&gt;state&lt;/em&gt; to manage this.&lt;/p&gt;
&lt;p&gt;Add the following property to the &lt;code&gt;ContentView&lt;/code&gt; struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct ContentView: View {
    
    // For driving animation to reveal rectangle with progress meter fill
    @State private var progressMeterOffset = CGSize.zero

    var body: some View {
        ...
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change the offset for the second rectangle so that it&#39;s offset is tied to the new   &lt;code&gt;progressMeterOffset&lt;/code&gt; property, which begins at zero:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.offset(progressMeterOffset)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;re back to having the rectangle that will slide up sitting directly on top of the rectangle behind it – save for the light blue outline, it again looks like there are no rectangles present at all.&lt;/p&gt;
&lt;p&gt;What to do?&lt;/p&gt;
&lt;p&gt;As soon as that second rectangle appears, we want it to move to its new position. So, &lt;em&gt;add&lt;/em&gt; the following modifier below the existing &lt;code&gt;offset&lt;/code&gt; modifier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.onAppear(perform: {
	// Offset is moves the opaque rectangle up
	progressMeterOffset = CGSize(width: 0, height: -1 * (548 - 44))
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tutorial probably doesn&#39;t feel very useful right now! 😅&lt;/p&gt;
&lt;p&gt;The rectangle that is to slide up now jumps &lt;em&gt;immediately&lt;/em&gt; to its new offset.&lt;/p&gt;
&lt;p&gt;It just looks like there is a single black rectangle – the view that represents the progress meter fill!&lt;/p&gt;
&lt;p&gt;The key is the addition of an animation, to make the transition between states occur over some defined period of time.&lt;/p&gt;
&lt;p&gt;Adjust the &lt;code&gt;onAppear&lt;/code&gt; view modifier as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.onAppear(perform: {
	withAnimation(Animation.easeIn(duration: 4.0)) {
		// Offset is moves the opaque rectangle up
		progressMeterOffset = CGSize(width: 0, height: -1 * (548 - 44))
	}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Initially&lt;/em&gt; the second rectangle has an offset of zero.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As soon as the second rectangle appears&lt;/em&gt;, the offset is changed to the new value.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The change in state&lt;/em&gt; between those two offsets is animated over the course of four seconds.&lt;/p&gt;
&lt;p&gt;At this point, you should see the following:&lt;/p&gt;
&lt;figure style=&quot;width: 310px;&quot;&gt;
	&lt;video width=&quot;310&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-rising-basic.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Basic progress meter&lt;/h4&gt;
		&lt;p&gt;As the view that matches the background color slides up using the animation, it reveals the view below it.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That&#39;s pretty nice, but before the animation is finished, we have no sense of the size of the progress meter, or how far progress is from &amp;quot;complete&amp;quot;.&lt;/p&gt;
&lt;p&gt;To do this, we need a border.&lt;/p&gt;
&lt;p&gt;Our first instinct would be to do just that – put a border on the rectangle in the background.&lt;/p&gt;
&lt;p&gt;Let&#39;s try that – add a &lt;code&gt;stroke&lt;/code&gt; modifier to the first rectangle:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// &amp;quot;Fill&amp;quot; for progress meter; stationary
Rectangle()
	.stroke(Color.primary, lineWidth: 4)
	.frame(width: 100, height: 548 - 44, alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the results are less than ideal.&lt;/p&gt;
&lt;p&gt;The rectangle that animates as it moves upward to a new offset makes our progress meter appear to have an open top.&lt;/p&gt;
&lt;p&gt;For that reason alone we need a different approach.&lt;/p&gt;
&lt;p&gt;Remove the &lt;code&gt;stroke&lt;/code&gt; modifier that we just added.&lt;/p&gt;
&lt;p&gt;Add a third rectangle enclosed within the &lt;code&gt;ZStack&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Sits above the rectangle that slides up (in the z-axis)
// This means the rectangle sliding up will pass beneath this view
Rectangle()
	.fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0))
	.frame(width: 100 + 2, height: 548 - 44 + 2, alignment: .center)
	.overlay(
		Rectangle()
			.stroke(Color.primary, lineWidth: 2)
	)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now have:&lt;/p&gt;
&lt;figure style=&quot;width: 310px;&quot;&gt;
	&lt;video width=&quot;310&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-rising-basic-with-border.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Progress meter with a border&lt;/h4&gt;
		&lt;p&gt;The top-most view on the &lt;em&gt;z&lt;/em&gt;-axis has a transparent fill. We see the other views below it, creating the appearance of a rising progress meter.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Let&#39;s break that down.&lt;/p&gt;
&lt;p&gt;First, the new rectangle that provides the border must have a transparent fill.&lt;/p&gt;
&lt;p&gt;Try commenting out the &lt;code&gt;fill&lt;/code&gt; modifier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;//	.fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&#39;ll notice we have a static image again. That&#39;s because the third view in the &lt;code&gt;ZStack&lt;/code&gt;, sitting above the other two views, has an opaque fill and border. We can&#39;t see what&#39;s happening beneath it.&lt;/p&gt;
&lt;p&gt;Uncomment the &lt;code&gt;fill&lt;/code&gt; modifier. More on hue, saturation, and brightness a little later. The key here is that &lt;code&gt;opacity&lt;/code&gt; is set to &lt;code&gt;0&lt;/code&gt;, which means that no matter what the color is, the fill is completely transparent.&lt;/p&gt;
&lt;p&gt;Next, you&#39;ll notice the width of the frame for this view is an expression, in this case, &lt;code&gt;100 + 2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.frame(width: 100 + 2, height: 548 - 44 + 2, alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rectangles below this one, on the &lt;em&gt;z&lt;/em&gt;-axis, also have a width of 100 points.&lt;/p&gt;
&lt;p&gt;By adding 2 points to the width of this topmost view, it ensures that the entire border will be visible, and that we can see the views underneath it.&lt;/p&gt;
&lt;p&gt;The final view modifier creates the border:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.overlay(
	Rectangle()
		.stroke(Color.primary, lineWidth: 2)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;eliminating-magic-constants&quot; tabindex=&quot;-1&quot;&gt;Eliminating Magic Constants&lt;/h2&gt;
&lt;p&gt;When teaching I encourage my students to start simple. That&#39;s what we&#39;ve done here, but a problem is starting to emerge in our code. Let&#39;s review – the entirety of &lt;code&gt;ContentView&lt;/code&gt; structure should now look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct ContentView: View {
    
    // For driving animation to reveal rectangle with progress meter fill
    @State private var progressMeterOffset = CGSize.zero
    
    var body: some View {
        VStack {
            ZStack {
                // &amp;quot;Fill&amp;quot; for progress meter; stationary
                Rectangle()
                    .frame(width: 100, height: 548 - 44, alignment: .center)

                // Will slide up
                Rectangle()
                    .fill(Color.primary)
                    .colorInvert()
                    .frame(width: 100, height: 548 - 44, alignment: .center)
                    .offset(progressMeterOffset)
                    .onAppear(perform: {
                        withAnimation(Animation.easeIn(duration: 4.0)) {
                            // Offset is moves the opaque rectangle up
                            progressMeterOffset = CGSize(width: 0, height: -1 * (548 - 44))
                        }
                    })

                // Sits above the rectangle that slides up (in the z-axis)
                // This means the rectangle sliding up will pass beneath this view
                Rectangle()
                    .fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0))
                    .frame(width: 100 + 2, height: 548 - 44 + 2, alignment: .center)
                    .overlay(
                        Rectangle()
                            .stroke(Color.primary, lineWidth: 2)
                    )

            }

        }

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve repeated several expressions. Let&#39;s say we wanted to make our progress meter a little wider. We&#39;d have to change arguments in three locations!&lt;/p&gt;
&lt;p&gt;This calls for the introduction of a constant property.&lt;/p&gt;
&lt;p&gt;Add the following to the structure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Width of the meter
let meterWidth: CGFloat = 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anywhere that you see the constant &lt;code&gt;100&lt;/code&gt;, replace this with the name of the constant, &lt;code&gt;meterWidth&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can do the same thing for the thickness of the border:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Thickness of meter&#39;s border
let borderWidth: CGFloat = 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anywhere that you see the constant &lt;code&gt;2&lt;/code&gt;, replace this with the name of the constant, &lt;code&gt;borderWidth&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the same can be done for the padding above and below the meter, which is currently set to 44 points&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; (22 points above, and 22 points below, since the view is vertically centred):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Padding above and below progress meter
let verticalPadding: CGFloat = 44
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anywhere that you see the constant &lt;code&gt;44&lt;/code&gt;, replace this with the name of the constant, &lt;code&gt;verticalPadding&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The code should now look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct ContentView: View {
    
    // For driving animation to reveal rectangle with progress meter fill
    @State private var progressMeterOffset = CGSize.zero
    
    // Width of the meter
    let meterWidth: CGFloat = 100

    // Thickness of meter&#39;s border
    let borderWidth: CGFloat = 2
    
    // Padding at top of progress meter
    let verticalPadding: CGFloat = 44
    
    var body: some View {
        VStack {
            ZStack {
                // &amp;quot;Fill&amp;quot; for progress meter; stationary
                Rectangle()
                    .frame(width: meterWidth, height: 548 - verticalPadding, alignment: .center)

                // Will slide up
                Rectangle()
                    .fill(Color.primary)
                    .colorInvert()
                    .frame(width: meterWidth, height: 548 - verticalPadding, alignment: .center)
                    .offset(progressMeterOffset)
                    .onAppear(perform: {
                        withAnimation(Animation.easeIn(duration: 4.0)) {
                            // Offset is moves the opaque rectangle up
                            progressMeterOffset = CGSize(width: 0, height: -1 * (548 - verticalPadding))
                        }
                    })

                // Sits above the rectangle that slides up (in the z-axis)
                // This means the rectangle sliding up will pass beneath this view
                Rectangle()
                    .fill(Color(hue: 0, saturation: 0, brightness: 0, opacity: 0))
                    .frame(width: meterWidth + borderWidth, height: 548 - verticalPadding + borderWidth, alignment: .center)
                    .overlay(
                        Rectangle()
                            .stroke(Color.primary, lineWidth: borderWidth)
                    )

            }

        }

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The advantage here is we can quickly make adjustments. Want less padding? Change &lt;code&gt;verticalPadding&lt;/code&gt; in one location. Want a thicker border? Adjust the &lt;code&gt;borderWidth&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Beyond convenience for adjusting the look of our progress meter, the code is simply more readable. We no longer have to think about what &lt;code&gt;100&lt;/code&gt; or &lt;code&gt;44&lt;/code&gt; represent when reviewing an expression. We can see what&#39;s happening by the property names we chose – the expressions are self-documenting.&lt;/p&gt;
&lt;p&gt;Try changing some of the new constants you just added and observing how that affects the animation.&lt;/p&gt;
&lt;p&gt;You&#39;re probably wondering – what about &lt;code&gt;548&lt;/code&gt;? When are we going to address that?&lt;/p&gt;
&lt;h2 id=&quot;using-geometry-reader-to-create-an-adaptive-layout&quot; tabindex=&quot;-1&quot;&gt;Using GeometryReader to Create an Adaptive Layout&lt;/h2&gt;
&lt;p&gt;Change the iOS simulator to be the &lt;strong&gt;iPhone 11 Pro Max&lt;/strong&gt;, or really any device larger than the iPod Touch.&lt;/p&gt;
&lt;p&gt;You see the problem with the remaining &amp;quot;magic constant&amp;quot; of &lt;code&gt;548&lt;/code&gt;:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-too-small.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Progress meter on a larger device&lt;/h4&gt;
		&lt;p&gt;548 points of height works on an iPod Touch, but not the iPhone 11 Pro Max.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To correct for this, we can place the &lt;code&gt;VStack&lt;/code&gt; and all its contents inside a &lt;code&gt;GeometryReader&lt;/code&gt; container view:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var body: some View {
	GeometryReader { geometry in
		VStack {
			...
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;NOTE: If you are using Xcode 11, after you place the &lt;code&gt;VStack&lt;/code&gt; inside &lt;code&gt;GeometryReader&lt;/code&gt;, you&#39;ll need to update references to properties to include the &lt;code&gt;self.&lt;/code&gt; prefix. If you&#39;re not sure what this means, don&#39;t worry, you&#39;ll see the red compiler warnings soon enough. 😅&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The developer documentation describes &lt;code&gt;GeometryReader&lt;/code&gt; as &amp;quot;[a] container view that defines its content as a function of its own size and coordinate space.&amp;quot;&lt;/p&gt;
&lt;p&gt;In practice, that means we can use the &lt;code&gt;geometry&lt;/code&gt; parameter to gain information about the size of the surrounding view.&lt;/p&gt;
&lt;p&gt;Temporarily comment out the &lt;code&gt;VStack&lt;/code&gt; and all it&#39;s contents, so that the only view inside  &lt;code&gt;GeometryReader&lt;/code&gt; is a &lt;code&gt;Text&lt;/code&gt; view like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Text(&amp;quot;Height is &#92;(geometry.size.height)&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On an iPhone 11 Pro Max, there are 818 points available to work with, vertically.&lt;/p&gt;
&lt;p&gt;If you wish, try changing to other simulators. You will see that the reported &lt;code&gt;geometry.size.height&lt;/code&gt; value changes accordingly.&lt;/p&gt;
&lt;p&gt;Now remove the &lt;code&gt;Text&lt;/code&gt; view and uncomment the &lt;code&gt;VStack&lt;/code&gt; and all its contents.&lt;/p&gt;
&lt;p&gt;Replace any reference to the constant &lt;code&gt;548&lt;/code&gt; with &lt;code&gt;geometry.size.height&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Try changing to other simulators.&lt;/p&gt;
&lt;p&gt;You will see that the progress meter now always fills the available vertical space. That&#39;s the power of &lt;code&gt;GeometryReader&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;As you&#39;ve surely also noticed, since moving our views inside &lt;code&gt;GeometryReader&lt;/code&gt;, the meter is no longer centred in the middle of the screen&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I&#39;m honestly not sure why this happens, but we can correct for it by judicious use of &lt;code&gt;Spacer&lt;/code&gt; views.&lt;/p&gt;
&lt;p&gt;To split the vertical padding evenly as we had before, just add &lt;code&gt;Spacer()&lt;/code&gt; views before and after the &lt;code&gt;ZStack&lt;/code&gt;, within the &lt;code&gt;VStack&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;VStack {
	
	Spacer()
	
	ZStack {
		...
	}
	
	Spacer()
	
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To centre the meter once again, we need to introduce an &lt;code&gt;HStack&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ll sandwich the &lt;code&gt;ZStack&lt;/code&gt; between two &lt;code&gt;Spacer&lt;/code&gt; views inside the horizontal stack:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;VStack {
	
	Spacer()
	
	HStack {
		
		Spacer()
		
		ZStack {
			...
		}
		
		Spacer()

	}
	
	Spacer()
	
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And just like that, we&#39;re back to having our progress meter positioned as before&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:4&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; except now it responds to varying device sizes:&lt;/p&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/adaptive-to-many-device-sizes.png&quot; loading=&quot;lazy&quot; alt=&quot;By using GeometryReader to interrogate the dimensions of the surrounding view, the progress meter can adapt to changes in screen size.&quot; style=&quot;width: 43%;&quot; /&gt; 
&lt;h2 id=&quot;a-name-xcode11-win-a-creating-a-colorful-progress-meter&quot; tabindex=&quot;-1&quot;&gt;&lt;a name=&quot;xcode11-win&quot;&gt;&lt;/a&gt;Creating a Colorful Progress Meter&lt;/h2&gt;
&lt;p&gt;In my youth I played video games more often. I recall enough about gaming to know that a &amp;quot;health meter&amp;quot; is usually red when a player is low on health, and green when things are going well.&lt;/p&gt;
&lt;p&gt;That&#39;s the inspiration for this next change to the progress meter.&lt;/p&gt;
&lt;p&gt;The closer it gets to &amp;quot;full&amp;quot; the more green we want the fill to be.&lt;/p&gt;
&lt;p&gt;I won&#39;t go into a full discourse on how to represent color on a computer here, because I am not an expert, and this article is already getting a bit long!&lt;/p&gt;
&lt;p&gt;Suffice it to say, the hue of a color can be represented as a value between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;360&lt;/code&gt; degrees. &lt;code&gt;0&lt;/code&gt; is red, &lt;code&gt;60&lt;/code&gt; degrees is yellow, &lt;code&gt;120&lt;/code&gt; degrees is green, and so on. You can see &lt;a href=&quot;https://russellgordon.ca/lcs/HSB_Color_Model_Summary_Swift.pdf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a few examples and read more here&lt;/a&gt;, if you like.&lt;/p&gt;
&lt;p&gt;What we will do is fill the progress meter with a gradient.&lt;/p&gt;
&lt;p&gt;The bottom, or start, of the gradient will always be red, so, &lt;code&gt;0&lt;/code&gt; degrees for a hue.&lt;/p&gt;
&lt;p&gt;The top, or end, of the gradient will be green if the progress meter is &amp;quot;full&amp;quot;, or something less than green if the progress meter is not full.&lt;/p&gt;
&lt;p&gt;First, we&#39;ll introduce a couple of constants to express how &amp;quot;full&amp;quot; the progress meter is. Since I wrote this progress meter initially to serve on a results screen &lt;a href=&quot;https://www.hackingwithswift.com/guide/ios-swiftui/3/3/challenge&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;for a multiplication practice app&lt;/a&gt;, the constants are named to reflect that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Needed data to calculate colors and size of meter
let correctResponses: Int = 10
let questionCount: Int = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The percentage of a full progress meter can be expressed with a computed property:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Percentage of full progress meter
// If the progress meter is full, this will equal 1.0
private var fractionOfFullMeter: Double {
	Double(correctResponses) / Double(questionCount)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the ending color of the gradient can also be expressed using a computed property:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Ending color for progress meter
// 120/360 degrees or 0.333 in Color struct terms is green
// which is the top of the meter when all questions are correct
private var endColor: Color {
	
	// If you had 10 out of 10 questions correct, this will equal 120.0 degrees
	let endingHue = fractionOfFullMeter * 120.0
	
	// Color is:
	// hue: 0-360 degrees, expressed as a value between 0 and 1
	// saturation: 0-100%, expressed as a value between 0 and 1
	// brightness: 0-100%, expressed as a value between 0 and 1
	// see: https://russellgordon.ca/lcs/HSB_Color_Model_Summary_Swift.pdf
	return Color(hue: endingHue / 360.0, saturation: 0.8, brightness: 0.9)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;ZStack&lt;/code&gt;, for the rectangle representing the fill of the progress meter (the first rectangle) add the following view modifier right before the &lt;code&gt;frame&lt;/code&gt; modifier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.fill(LinearGradient(gradient: Gradient(colors: [Color.red, endColor]),
					 startPoint: .bottom,
					 endPoint: .top))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you added the constants, the computed property, and the &lt;code&gt;fill&lt;/code&gt; modifier correctly, you should now have this:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-with-color.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Applying a gradient&lt;/h4&gt;
		&lt;p&gt;As the progress meter approaches completion, the colour moves from red to green.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We are not quite finished, however. Reduce the correct responses constant:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let correctResponses: Int = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Review the animation:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-with-color-wrong-height.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;An incorrect height&lt;/h4&gt;
		&lt;p&gt;At present, while colors are accurate, the progress bar always appears to be complete.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The gradient works as expected, since it barely gets out of the orange range of hues, given that there were only three correct responses out of ten.&lt;/p&gt;
&lt;p&gt;However, the height of the progress bar is not accurate.&lt;/p&gt;
&lt;p&gt;We can correct that by using the &lt;code&gt;fractionOfFullMeter&lt;/code&gt; property to reduce the height of the rectangle that contains the fill of the progress meter.&lt;/p&gt;
&lt;p&gt;Change the view modifier for the size of the frame on the first rectangle from the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.frame(width: meterWidth, height: geometry.size.height - verticalPadding, alignment: .center)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... to this instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;.frame(width: meterWidth, height: CGFloat(fractionOfFullMeter) * (geometry.size.height - verticalPadding), alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The animation will now look like this:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-with-color-correct-height-wrong-placement.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Oooh, so close!&lt;/h4&gt;
		&lt;p&gt;Can you predict what we need to do?&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The rectangle containing the view is centred vertically in the &lt;code&gt;ZStack&lt;/code&gt; that contains it.&lt;/p&gt;
&lt;p&gt;There are a couple of ways this could be handled, but we&#39;ll correct the problem by adding another rectangle above the progress meter, inside a &lt;code&gt;VStack&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Change this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;ZStack {

	// &amp;quot;Fill&amp;quot; for progress meter; stationary
	Rectangle()
		.fill(LinearGradient(gradient: Gradient(colors: [Color.red, endColor]),
							 startPoint: .bottom,
							 endPoint: .top))
		.frame(width: meterWidth, height: CGFloat(fractionOfFullMeter) * (geometry.size.height - verticalPadding), alignment: .center)
		
	...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;ZStack {

	VStack(spacing: 0) {
		
		// This pushes the filled part of the progress meter down
		Rectangle()
			.frame(width: meterWidth, height: (geometry.size.height - verticalPadding) - CGFloat(fractionOfFullMeter) * (geometry.size.height - verticalPadding), alignment: .center)
		
		// &amp;quot;Fill&amp;quot; for progress meter; stationary
		Rectangle()
			.fill(LinearGradient(gradient: Gradient(colors: [Color.red, endColor]),
								 startPoint: .bottom,
								 endPoint: .top))
			.frame(width: meterWidth, height: CGFloat(fractionOfFullMeter) * (geometry.size.height - verticalPadding), alignment: .center)

	}
	
	...

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the addition of the &lt;code&gt;spacing&lt;/code&gt; parameter with an argument of &lt;code&gt;0&lt;/code&gt; on the &lt;code&gt;VStack&lt;/code&gt;. That ensures the two rectangles in the &lt;code&gt;VStack&lt;/code&gt; will sit snugly against one another.&lt;/p&gt;
&lt;p&gt;At this point, you will see the following:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-with-color-correct-height-correct-placement-black-fill.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;The new rectangle&#39;s fill was left black so that we can see where it exists.&lt;/p&gt;
&lt;p&gt;Now, we can add a couple of view modifiers to change it&#39;s fill to match the background color of the view:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// This pushes the filled part of the progress meter down
Rectangle()
	.fill(Color.primary)
	.colorInvert()
	.frame(width: meterWidth, height: (geometry.size.height - verticalPadding) - CGFloat(fractionOfFullMeter) * (geometry.size.height - verticalPadding), alignment: .center)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our progress meter, from it&#39;s outward apperance at least, is now complete!&lt;/p&gt;
&lt;p&gt;Try changing the &lt;code&gt;correctRespones&lt;/code&gt; constant to different values to see the effect it has on the animation:&lt;/p&gt;
&lt;figure style=&quot;width: 367px;&quot;&gt;
	&lt;video width=&quot;367&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/progress-meter-complete-various-values.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;The completed progress meter&lt;/h4&gt;
		&lt;p&gt;What the animation looks like with three, seven, and ten out of ten questions completed correctly.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;creating-a-composable-view&quot; tabindex=&quot;-1&quot;&gt;Creating a Composable View&lt;/h2&gt;
&lt;p&gt;We now have a progress meter that is reasonably well put together, but if we wish to combine it with other parts of an app (as I did with a multiplication practice app) it would be best if what we&#39;ve done so far was defined as part of its own type. Let&#39;s call this new type &lt;code&gt;ProgressMeter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Rather than provide a long series of steps to follow, you can just download a &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/ProgressMeterXcode12.zip&quot;&gt;complete Xcode 12 project&lt;/a&gt; where this has already been done, or &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/ProgressMeterXcode11.zip&quot;&gt;here for an Xcode 11 project&lt;/a&gt;. If you prefer, you can get the &lt;a href=&quot;https://github.com/russellgordon/ProgressMeterXcode12&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Xcode 12 project from GitHub here&lt;/a&gt;, or the &lt;a href=&quot;https://github.com/russellgordon/ProgressMeterXcode11&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Xcode 11 project from GitHub here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note that in &lt;code&gt;ProgressMeter.swift&lt;/code&gt;, the constants:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Width of the meter
let meterWidth: CGFloat = 100

// Thickness of meter&#39;s border
let borderWidth: CGFloat = 2

// Padding above and below progress meter
let verticalPadding: CGFloat = 44

// Needed data to calculate colors and size of meter
let correctResponses: Int = 10
let questionCount: Int = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... have been changed to variables without initial values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;// Width of the meter
var meterWidth: CGFloat

// Thickness of meter&#39;s border
var borderWidth: CGFloat

// Padding above and below progress meter
var verticalPadding: CGFloat

// Needed data to calculate colors and size of meter
var correctResponses: Int
var questionCount: Int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That means to use an instance of the &lt;code&gt;ProgressMeter&lt;/code&gt; view, we must provide values for those properties.&lt;/p&gt;
&lt;p&gt;This is done in &lt;code&gt;ContentView.swift&lt;/code&gt; where we now just create an instance of &lt;code&gt;ProgressMeter&lt;/code&gt; and pass in the required arguments:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;ProgressMeter(meterWidth: 100, borderWidth: 2, verticalPadding: 44, correctResponses: 10, questionCount: 10)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, we now have a self-contained view that can be neatly composed together with other views in a larger app and re-used in multiple future projects.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This turned out to be a rather lengthy tutorial. If you&#39;ve found it helpful, interesting, or have found an error &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;please tell me&lt;/a&gt;. Thanks for reading this far! 😅&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;I&#39;ve been working through Paul Hudson&#39;s &lt;a href=&quot;https://www.hackingwithswift.com/100&quot;&gt;100 Days of SwiftUI tutorials&lt;/a&gt;. Highly recommended.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;Why 44 points? No particular reason – that&#39;s just the amount of padding I felt looked good when I initially wrote this progress meter view.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:2&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;This doesn&#39;t seem to happen with Xcode 11, and probably represents a bug in the beta of Xcode 12 I was using when authoring this article. So, if you&#39;re seeing the progress meter stay centred, feel free to &lt;a href=&quot;https://russellgordon.dev/#xcode11-win&quot;&gt;skip ahead to this part&lt;/a&gt; of the tutorial.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:3&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;I &lt;em&gt;love&lt;/em&gt; spacer views.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:4&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt; 
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/building-an-animated-progress-meter-view-with-swiftui/" />
        </entry>
    
    
        <entry>
            <title>
                Adding a Physical Device as a Run Destination
                
            </title>
            <updated>2020-09-19T19:29:00.000Z</updated>
            <id>https://russellgordon.dev//tutorials/adding-a-physical-device-as-a-run-destination/</id>
            <content type="html">
                &lt;p&gt;To run applications you write in Xcode on your iPhone or iPad, a few one-time-only setup steps are required.&lt;/p&gt;
&lt;p&gt;First, be sure Xcode is open.&lt;/p&gt;
&lt;p&gt;Select the menu sequence &lt;strong&gt;Window&lt;/strong&gt; → &lt;strong&gt;Devices and Simulators&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Then, connect your iPhone or iPad to your Mac using a cable.&lt;/p&gt;
&lt;p&gt;The first time you do this, you will see an image something like this:&lt;/p&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/making-ready-for-development.png&quot; loading=&quot;lazy&quot; alt=&quot;Devices and simulators window reporting that files are being copied to make a device ready for development.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The yellow banner message is telling you that certain required files are being copied to and from your device.&lt;/p&gt;
&lt;p&gt;That process may take a few minutes to complete; be patient. When it is finished, the yellow banner will disappear.&lt;/p&gt;
&lt;p&gt;Next, you can select the device you&#39;ve connected as a run destination.&lt;/p&gt;
&lt;p&gt;At the top left of the primary Xcode window, click the list of devices:&lt;/p&gt;
&lt;figure style=&quot;width: 542px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/device-list.png&quot; loading=&quot;lazy&quot; alt=&quot;Where to select a device as a run destination.&quot; width=&quot;542&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Then select your device from the list (a connected physical device is always at the top of the list):&lt;/p&gt;
&lt;figure style=&quot;width: 560px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/selecting-a-device.png&quot; loading=&quot;lazy&quot; alt=&quot;Making a device selection.&quot; width=&quot;560&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Now build the application:&lt;/p&gt;
&lt;figure style=&quot;width: 516px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/build.png&quot; loading=&quot;lazy&quot; alt=&quot;Building the application.&quot; width=&quot;516&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To use your developer certificate with the device, you&#39;ll need to allow access to your computer&#39;s keychain. Select &lt;strong&gt;Always Allow&lt;/strong&gt; so that you don&#39;t have to do this every time you build an app for the device:&lt;/p&gt;
&lt;figure style=&quot;width: 546px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/code-signing.png&quot; loading=&quot;lazy&quot; alt=&quot;Providing permission to access your development certificate in your computer&#39;s keychain.&quot; width=&quot;546&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Next, you will likely see a message indicating that Xcode cannot run the application on the device, because, essentially, your iPhone or iPad currently does not &amp;quot;trust&amp;quot; the Mac that you are developing on to install applications upon it.&lt;/p&gt;
&lt;p&gt;To create that trust, follow the &lt;a href=&quot;https://blog.frd.mn/ios-9-and-untrusted-developer-message/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;instructions shown here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The next time you build your application with your iPhone or iPad as the selected run destination, after a few seconds, you should see it open on your device.&lt;/p&gt;
&lt;p&gt;Have fun! 🚀&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tutorials/adding-a-physical-device-as-a-run-destination/" />
        </entry>
    
    
    
    
        <entry>
            <title>
                Prevent the Dreaded Blue Screen of Death
                
            </title>
            <updated>2020-08-10T22:30:32.000Z</updated>
            <id>https://russellgordon.dev//tips/prevent-the-dreaded-blue-screen-of-death/</id>
            <content type="html">
                &lt;p&gt;No, not that &lt;a href=&quot;https://duckduckgo.com/?q=blue+screen+of+death&amp;amp;t=osx&amp;amp;iax=images&amp;amp;ia=images&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;blue screen of death&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://1.bp.blogspot.com/--MHob14Id2Q/WHcK-Kev7vI/AAAAAAAAAdI/MvzrUCLRBCwLy1NNUyn2aIGZcX_JpqLWACLcB/s1600/Epson-EB-X31-PM04.jpeg&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;This one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;ve all been there: in front of a class, or perhaps colleagues, hitting our speaking groove – and then the slide deck drops out and the projector complains that there is no input.&lt;/p&gt;
&lt;p&gt;This is caused when the connected computer goes to sleep due to a lack of keyboard or trackpad input.&lt;/p&gt;
&lt;p&gt;In the run up to a class or presentation, remembering to adjust energy saver settings can be pretty far down the priority list.&lt;/p&gt;
&lt;p&gt;A utility called &lt;a href=&quot;https://intelliscapesolutions.com/apps/caffeine&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Caffeine&lt;/a&gt;, appropriately, comes to the rescue.&lt;/p&gt;
&lt;p&gt;This is a small program that lives in the menu bar of your Mac. The preferences are very basic:&lt;/p&gt;
&lt;figure style=&quot;width: 421px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/preferences.png&quot; loading=&quot;lazy&quot; alt=&quot;Preferences window for Caffeine app on macOS.&quot; width=&quot;421&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;To get Caffeine, &lt;a href=&quot;https://intelliscapesolutions.com/apps/caffeine&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;download it&lt;/a&gt;, then double-click the &lt;code&gt;Caffeine.dmg&lt;/code&gt; file. Drag the Caffeine icon to your Applications folder.&lt;/p&gt;
&lt;p&gt;When you run the program for the first time, you can select your preferences.&lt;/p&gt;
&lt;p&gt;As a matter of course while teaching, I always keep Caffeine enabled.&lt;/p&gt;
&lt;p&gt;If I want my laptop to sleep, I close the lid or explicitly put it to sleep.&lt;/p&gt;
&lt;p&gt;And I never, ever encounter the blue screen of death. 😅&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tips/prevent-the-dreaded-blue-screen-of-death/" />
        </entry>
    
    
        <entry>
            <title>
                Embiggen Text Like a Pro
                
            </title>
            <updated>2020-08-11T22:30:32.000Z</updated>
            <id>https://russellgordon.dev//tips/embiggen-text-like-a-pro/</id>
            <content type="html">
                &lt;blockquote&gt;
&lt;p&gt;A noble spirit embiggens the smallest man.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;– Springfield town motto&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the seventh-season episode &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisa_the_Iconoclast&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Lisa the Iconoclast&lt;/a&gt; &lt;em&gt;The Simpsons&#39;&lt;/em&gt; writers popularized a word that, it turns out, has been used as far back as 1884.&lt;/p&gt;
&lt;p&gt;Why mention this? I&#39;ve a perfectly cromulent reason.&lt;/p&gt;
&lt;p&gt;When teaching, whether live or through video, it&#39;s helpful at times to make something that&#39;s rather small on your screen temporarily show up much larger.&lt;/p&gt;
&lt;p&gt;Need to highlight a key term? Indicate that a new section of a video is beginning? Have an off-the-cuff need to send students to a website?&lt;/p&gt;
&lt;p&gt;These are all use cases for embiggening text.&lt;/p&gt;
&lt;h2 id=&quot;installing-large-type2&quot; tabindex=&quot;-1&quot;&gt;Installing LargeType2&lt;/h2&gt;
&lt;p&gt;On macOS&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; the &lt;a href=&quot;https://blyt.net/algrtepy2e/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LargeType2 utility&lt;/a&gt; makes this possible. Here is an example:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/example-dark.jpg&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/example-light.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Small text in a sticky note is made large enough to fill the screen.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;&lt;a href=&quot;https://blyt.net/algrtepy2e/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Download the program&lt;/a&gt;, open the disk image, and drag the LargeType icon to your Applications folder.&lt;/p&gt;
&lt;p&gt;Now navigate to your Applications folder and open LargeType2. On more recent versions of macOS, you will encounter a message like this one:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/warning-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/warning-light.png&quot; loading=&quot;lazy&quot; alt=&quot;macOS security warning explaining that LargeType2 cannot be checked for malicious software.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;This message appears on first run because LargeType2 has not been updated recently. While it still works just fine on macOS, this warning message appears because the application is not digitally signed by the developer. I have been using this application for years. It&#39;s not malware. You can work around the security warning by two-finger tapping, or context-clicking, the application, and choosing &lt;strong&gt;Open&lt;/strong&gt;:&lt;/p&gt;
&lt;picture&gt;
	&lt;source srcset=&quot;https://russellgordon.dev/img/user/Media/open-anyway-dark.png&quot; media=&quot;(prefers-color-scheme: dark)&quot; /&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/open-anyway-light.png&quot; loading=&quot;lazy&quot; alt=&quot;Working around the macOS security warning by selecting the LargeType2 application in Finder and choosing Open from the context menu.&quot; /&gt; 
&lt;/picture&gt;
&lt;p&gt;In the dialog that appears, select &lt;strong&gt;Open&lt;/strong&gt; again.&lt;/p&gt;
&lt;p&gt;At this point you will see a small instructions window. You need to log out of macOS and then log back in. If you are the only user of your Mac, and don&#39;t use a login window, you&#39;ll need to restart your computer.&lt;/p&gt;
&lt;h2 id=&quot;configuring-a-keyboard-shortcut&quot; tabindex=&quot;-1&quot;&gt;Configuring a Keyboard Shortcut&lt;/h2&gt;
&lt;p&gt;Now that LargeType2 is installed, you can highlight any text, two-finger tap or context-click, select Services, and then LargeType.&lt;/p&gt;
&lt;p&gt;That&#39;s a bit awkward, so let&#39;s set up a keyboard shortcut.&lt;/p&gt;
&lt;p&gt;To do so:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open System Preferences.&lt;/li&gt;
&lt;li&gt;Navigate to the Keyboard preference pane.&lt;/li&gt;
&lt;li&gt;Select the Shortcuts tab.&lt;/li&gt;
&lt;li&gt;Select Services at left.&lt;/li&gt;
&lt;li&gt;In the list at right, scroll down to LargeType.&lt;/li&gt;
&lt;li&gt;Select the LargeType entry. Click where it says &lt;em&gt;Add Shortcut&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Now choose a keyboard combination that will embiggen text. I like Control-Option-Command-L. These are the three modifier keys to the left of the spacebar on my keyboard, so it&#39;s easy to remember, and won&#39;t conflict with other application keyboard shortcuts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&#39;s a long list of steps, so if you prefer, &lt;a href=&quot;https://www.youtube.com/embed/GQXMmCi1uMI&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;here&#39;s a short video showing how that works&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-payoff&quot; tabindex=&quot;-1&quot;&gt;The Payoff&lt;/h2&gt;
&lt;p&gt;Now you&#39;re all set for rapid embiggening!&lt;/p&gt;
&lt;p&gt;Just select text in any application, hit your keyboard shortcut, and enjoy your very large text.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;Sorry, Windows users. I&#39;ve been on macOS for fifteen years so I&#39;m not going to be very useful to you. If anyone knows of a utility similar to LargeType that runs on Windows, &lt;a href=&quot;mailto:contact@russellgordon.ca&quot;&gt;let me know&lt;/a&gt;, and I&#39;ll insert an addendum to this tip. &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const teaching = document.getElementById(&quot;rwhg-navigation-teaching&quot;);
	teaching.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//tips/embiggen-text-like-a-pro/" />
        </entry>
    
    
    
    
        <entry>
            <title>
                Snow Clearing and Computer Studies Enrolment
                
            </title>
            <updated>2019-08-14T13:22:00.000Z</updated>
            <id>https://russellgordon.dev//teaching/snow-clearing-and-computer-studies-enrolment/</id>
            <content type="html">
                &lt;p&gt;What impacts Computer Studies enrolment in Ontario?&lt;/p&gt;
&lt;p&gt;There&#39;s the &lt;em&gt;chicken and egg problem&lt;/em&gt;, for one. Our courses are not prerequisites for &lt;a href=&quot;https://en.wikipedia.org/wiki/Science,_technology,_engineering,_and_mathematics&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;STEM&lt;/a&gt;-related majors in Ontario universities... because not all secondary schools in Ontario offer Computer Studies courses. It&#39;s hard to require a course that is not offered. That&#39;s &lt;a href=&quot;https://www.thestar.com/politics/provincial/2019/07/08/ontarios-new-class-size-means-toronto-york-school-boards-forced-to-cut-stem-classes.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;only going to get worse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There&#39;s a perception that our courses are &lt;em&gt;difficult&lt;/em&gt;. Any student who has spent inordinate amounts of time struggling with syntax will agree that can be true (even if it&#39;s really &lt;a href=&quot;http://worrydream.com/#!/LearnableProgramming&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the tools that are deficient&lt;/a&gt; and not the programmer).&lt;/p&gt;
&lt;p&gt;And then... there&#39;s this, from the lede on a &lt;a href=&quot;https://99percentinvisible.org/episode/invisible-women/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;recent episode of 99% Invisible&lt;/a&gt; by &lt;a href=&quot;http://romanmars.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Roman Mars&lt;/a&gt;, interviewing &lt;a href=&quot;https://www.carolinecriadoperez.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Caroline Criado Perez&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Today’s show is about a design flaw that might be, and I’m not exaggerating here, the single-most common design flaw in human history. It potentially affects everything we have ever built. Its consequences are felt by more than half of people worldwide...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;What&#39;s this now?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There&#39;s a town in Sweden. Karlskoga. It snows there. For a long time, like many places, when it snowed, major roads were cleared first. In the process of doing a gender analysis of local town policies, someone made a joke – &lt;em&gt;snow clearing&lt;/em&gt;. It couldn&#39;t possibly have anything to do with gender, could it?&lt;/p&gt;
&lt;p&gt;Karlskoga city planners looked at the types of tasks  women handle on a daily basis. Tasks like shuttling children to school, stopping off to pick up groceries, dropping in to check on elderly relatives. Tasks that were often completed on foot or by taking public transit on smaller residential roads.&lt;/p&gt;
&lt;p&gt;It turns out... it&#39;s a lot harder, and much less safe, to push a stroller through a foot of snow than it is to drive a car down a major arterial road. Karlskoga decided to clear minor roads and residential areas first, and saw a significant decrease in healthcare costs, savings that far outweighed the cost of winter road maintenance. &lt;em&gt;Everyone benefits.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What if, by making deliberate choices about how we describe, promote, and deploy our Computer Studies courses, we bring in not just more young women, but more students overall to this vital field of endeavour?&lt;/p&gt;
&lt;h2 id=&quot;context-over-tools&quot; tabindex=&quot;-1&quot;&gt;Context Over Tools&lt;/h2&gt;
&lt;p&gt;I recently visited Austin, Texas to attend a weeklong workshop with teachers using &lt;a href=&quot;https://swift.org/about/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Swift&lt;/a&gt; for instruction in the College Board&#39;s Advanced Placement &lt;a href=&quot;https://apcentral.collegeboard.org/courses/ap-computer-science-principles&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Computer Science Principles&lt;/a&gt; course.&lt;/p&gt;
&lt;p&gt;The workshop was hosted by Apple, and we naturally spent time examining &lt;a href=&quot;https://www.apple.com/everyone-can-code/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;their curricular resources&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/xcode/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was pleased to see that the agenda focused not just on tools, but also on the bigger picture of inclusion in the software industry and in our classrooms. &lt;a href=&quot;http://www.kiang.net/interests.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Douglas Kiang&lt;/a&gt; gave an excellent talk on fostering a sense of belonging for young women in computer science courses.&lt;/p&gt;
&lt;p&gt;With permission from Douglas, I will include text from a few of his presentation slides here.&lt;/p&gt;
&lt;p&gt;The following is an older description for a course offered at &lt;a href=&quot;https://www.punahou.edu/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Douglas&#39; school&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Introduction to JavaScript (1 credit)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;
This course introduces students to the basics of JavaScript, HTML,   and CSS. It covers basic computer programming concepts such as variables, loops, operators, arrays, functions, and conditional statements. It features best practices for current web-standards compliance techniques using the HTML DOM (Document Object Model) and offers interested students the opportunity to dive deeper into asynchronous data requests using AJAX and jQuery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The question Douglas posed: &lt;em&gt;Who is your audience?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To whom does that original course description speak?&lt;/p&gt;
&lt;p&gt;As teachers, we understand it. Would a student?&lt;/p&gt;
&lt;p&gt;It&#39;s kind of like seeing a course description like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Introduction to Japanese (1 credit)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;
基本クラスは、基本的な⽂文法に注意を払いながら、コミュニケーションスキル (主に会話型)を身に付けることを⽬目的としています。 中級クラスは、基本レベ ルの⽂文型を組み合わせることにより、実⽤用的な会話能⼒力力をさらに⾼高めることを⽬目 的としています。 各グループは週に1回、⽇日本⼈人ボランティアによる約90分の レッスンを受けます。 参加者のスケジュールが特定の⽇日の出席を許可しない場 合、会議は⾒見見逃される可能性があります。 授業内容は、グループの規模と参加者 の興味と能⼒力力に応じて調整されます。 基本的な焦点は、⽇日常⽣生活や勉勉強に必要な ⽇日本語の会話⼒力力を伸ばし、⽇日本の⽂文化や伝統について指導することです。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Douglas and his colleagues revised the course description to read as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Building Websites for Non-Profits (1 credit + community service)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;
Work closely with a community organization to help design a website that meets their needs. Gain programming experience while designing a front-end web interface that retrieves data from a server. Previous projects have included an event registration page for Malama Honua, an after-school program site for the Boys and Girls Club, and a web portal for the Arcadia Retirement Residence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Same course, same content, different description.&lt;/p&gt;
&lt;p&gt;The result? Punahou School school saw many more young women enrol, as well as more young men.&lt;/p&gt;
&lt;p&gt;Students in Ontario will always see the standard Ministry of Education course descriptions in official documentation.&lt;/p&gt;
&lt;p&gt;However, it&#39;s the very definition of &lt;em&gt;picking the low hanging fruit&lt;/em&gt; for us, as teachers, to provide the Guidance staff, students, and parents at our schools with accessible and welcoming course descriptions, and ensure that these are made visible to students well in advance of course selection time.&lt;/p&gt;
&lt;p&gt;How we &lt;em&gt;describe&lt;/em&gt; what we do in our courses matters.&lt;/p&gt;
&lt;h2 id=&quot;build-community&quot; tabindex=&quot;-1&quot;&gt;Build Community&lt;/h2&gt;
&lt;p&gt;For the first time in my teaching career&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, the gender balance in my Computer Studies classes across grades 10 and 11 is precisely even. At last check, there are seven boys and ten girls enrolled in ICS2O; eleven boys and eight girls in ICS3U.&lt;/p&gt;
&lt;p&gt;With few other variables in the mix, I&#39;m left to cautiously conclude that new opportunities we offered last year at &lt;a href=&quot;https://www.lcs.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Lakefield College School&lt;/a&gt; have made a difference for enrolment this year.&lt;/p&gt;
&lt;p&gt;First, in December 2018, my school partnered with the Hackergal team to participate in &lt;a href=&quot;https://twitter.com/hashtag/hackergal2018&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a hackathon&lt;/a&gt;. In &lt;a href=&quot;https://www.hackergal.org/how-it-works/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;their words&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Hackathon is an event in which groups of people &lt;strong&gt;come together to solve a problem&lt;/strong&gt;. The term is largely used in the tech industry to describe a fast-paced event in which computer programmers or “coders” work together to create a functioning product. During a Hackergal Hackathon, &lt;strong&gt;groups of girls work together&lt;/strong&gt; over a day to &lt;strong&gt;apply coding skills&lt;/strong&gt; they’ve learned leading up to Hackathon Day. Teams &lt;strong&gt;will work together to create an interactive project&lt;/strong&gt; with a theme that is revealed on the morning of the Hackathon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To prepare for the hackathon, we had twelve grade 9 girls complete five lessons over roughly ten hours of co-curricular time.&lt;/p&gt;
&lt;p&gt;The Hackergal organization provided all of the preparatory material and tools free of charge, and were extremely strong communicators leading up to the event itself.&lt;/p&gt;
&lt;p&gt;On the day of the hackathon, the girls were excused from class and completed the challenge along with a much larger group of young women across the country through an online presence.&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet tw-align-center&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Our students are taking part today’s &lt;a href=&quot;https://twitter.com/thehackergals?ref_src=twsrc%5Etfw&quot;&gt;@thehackergals&lt;/a&gt;’ Canada-wide hackathon with girls from more than 100 schools across Canada. &lt;a href=&quot;https://twitter.com/hashtag/becausewecan?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;&lt;a class=&quot;tag&quot; onclick=&quot;toggleTagSearch(this)&quot; data-content=&quot;#becausewecan&quot;&gt;#becausewecan&lt;/a&gt;&lt;/a&gt; &lt;a href=&quot;https://twitter.com/hashtag/hackergal2018?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;&lt;a class=&quot;tag&quot; onclick=&quot;toggleTagSearch(this)&quot; data-content=&quot;#hackergal2018&quot;&gt;#hackergal2018&lt;/a&gt;&lt;/a&gt; &lt;a href=&quot;https://t.co/mVi7SbfXQS&quot;&gt;pic.twitter.com/mVi7SbfXQS&lt;/a&gt;&lt;/p&gt;&amp;mdash; Lakefield College (@LakefieldCS) &lt;a href=&quot;https://twitter.com/LakefieldCS/status/1072906531727917056?ref_src=twsrc%5Etfw&quot;&gt;December 12, 2018&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;As a strategy, advocating for and offering an event like this takes more time than re-writing course descriptions – but it created an amazing sense of community among the young women at our school before they even got to the point of considering enrolment in a computer studies course.&lt;/p&gt;
&lt;h2 id=&quot;provide-a-trial-run&quot; tabindex=&quot;-1&quot;&gt;Provide a Trial Run&lt;/h2&gt;
&lt;p&gt;Developers often allow users to try out their software prior to asking for the commitment of a payment.&lt;/p&gt;
&lt;p&gt;In the same vein, at LCS, we offered a coding-themed day to coincide with &lt;a href=&quot;https://csedweek.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Computer Science Education Week&lt;/a&gt;. The timing here is deliberate –  positioned in advance of (but not too far before) course selection on the school calendar.&lt;/p&gt;
&lt;p&gt;On an &lt;em&gt;intercession day&lt;/em&gt; at LCS – when the entire school has a break from regular classes, but the learning continues through other tasks – students had (among other options) the opportunity to participate in a day of coding-related activities.&lt;/p&gt;
&lt;p&gt;Tasks offered included the creation of physical artwork by &lt;a href=&quot;https://www.turtlestitch.org/run&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;generating SVG files through code&lt;/a&gt; and then sending the files &lt;a href=&quot;https://shop.evilmadscientist.com/846&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;to a plotter&lt;/a&gt;:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;video width=&quot;568&quot; height=&quot;&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/plotter-output.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Generating Physical Artwork Using Code&lt;/h4&gt;
		&lt;p&gt;Any programming environment capable of generating an SVG file can be used to drive the output on an AxiDraw plotter.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Senior students enrolled in Computer Studies courses mentored junior students who expressed an interest in starting to prepare for computer science contests, using online coding environments like &lt;a href=&quot;https://repl.it/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;repl.it&lt;/a&gt; and &lt;a href=&quot;https://cemc.uwaterloo.ca/contests/past_contests.html#ccc&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;past problems published by the CEMC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another option saw students use &lt;a href=&quot;https://processing.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Processing&lt;/a&gt; to explore &lt;a href=&quot;https://processing.org/tutorials/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;introductory tutorials&lt;/a&gt; explaining how to produce graphics and animations, with more experienced students digging into the work of &lt;a href=&quot;http://reas.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;generative artists&lt;/a&gt; or &lt;a href=&quot;https://natureofcode.com/book/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;simulating natural systems&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The centrepiece of the day involved &lt;a href=&quot;https://mycommunity.trentu.ca/2015-community/trent-talkshigh-school-edition&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a visit from a Dr. Rachel Wortis&lt;/a&gt; from  Trent University who gave a hands-on talk about &lt;a href=&quot;https://mycommunity.trentu.ca/community/talks#Wortis&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;encryption and quantum computing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The day, to be honest, was a lot of work to organize, but it doesn&#39;t have to be that way.&lt;/p&gt;
&lt;p&gt;In the future, we plan to run a similar day at &lt;a href=&quot;https://www.lcs.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;LCS&lt;/a&gt;, but may make more use of externally sourced content that does not necessarily involve coding, such as the popular &lt;a href=&quot;https://medium.com/@cs50/this-was-cs50x-puzzle-day-2018-22d95a48615&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;CS50 Puzzle Day&lt;/a&gt; authored by David J. Malan and his team at Harvard, or the &lt;a href=&quot;https://www.collegepuzzlechallenge.com/About.aspx&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;College Puzzle Challenge&lt;/a&gt; provided by Microsoft.&lt;/p&gt;
&lt;p&gt;The theme of the series of activities was to provide students with a taste of what computer studies is all about before those students need to make a choice about course selection.&lt;/p&gt;
&lt;p&gt;How we &lt;em&gt;promote&lt;/em&gt; computer studies matters.&lt;/p&gt;
&lt;h2 id=&quot;positive-role-models&quot; tabindex=&quot;-1&quot;&gt;Positive Role Models&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;When it comes to recruiting women into computer science, &lt;mark&gt;whether a role model projects current stereotypes of the field&lt;/mark&gt; may be &lt;mark&gt;more important than whether that role model is female or male&lt;/mark&gt;. Role models may be successful if they elicit a sense of belonging.&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Douglas Kiang emphasized those points during &lt;a href=&quot;https://russellgordon.dev/#context-over-tools&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;his talk in Austin&lt;/a&gt; in July.&lt;/p&gt;
&lt;p&gt;During &lt;a href=&quot;https://russellgordon.dev/#provide-a-trial-run&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;that same intercession day&lt;/a&gt; in early December at LCS we arranged for several graduates of my past classes to speak with current students through video chats.&lt;/p&gt;
&lt;p&gt;The speakers – two young women, three young men – do not all exclusively write code in their positions. None hew to Hollywood hacker stereotypes. Of the speakers we were fortunate to ask questions of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;two are developers at Apple (iPhone and Watch teams)&lt;/li&gt;
&lt;li&gt;one is an analyst at KPMG&lt;/li&gt;
&lt;li&gt;one is a project manager at Yelp&lt;/li&gt;
&lt;li&gt;the final speaker works in a variety of roles exploring the intersection of visual arts, business, and technology (she is about to graduate &lt;a href=&quot;https://iovine-young.usc.edu/about/index.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;from this fascinating program at USC&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, I had not yet heard Douglas make his point when I organized speakers. What he said resonated, however, and the response from LCS students was positive.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/guest-speaker.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A young woman takes part in a video chat with current high school students.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Question and Answer&lt;/h4&gt;
	&lt;p&gt;A past graduate of my computer studies classes talks with current LCS students.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The key here – whether we find role models in past students, parents in a school&#39;s community, or members of the public – it is helpful to show current students where our courses lead – before they are asked to decide on course selection.&lt;/p&gt;
&lt;h2 id=&quot;embrace-the-depth-of-the-field&quot; tabindex=&quot;-1&quot;&gt;Embrace the Depth of the Field&lt;/h2&gt;
&lt;p&gt;If you&#39;ve been paying close attention, you&#39;ve noticed that I have used the term &lt;em&gt;computer studies&lt;/em&gt; throughout this article – not &lt;em&gt;computer science&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That is deliberate – the former is a superset of the latter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;mark&gt;Computer studies&lt;/mark&gt; is about how computers compute. It is not about learning how to use the computer, and it &lt;mark&gt;is much more than computer programming&lt;/mark&gt;. Computer studies is the study of ways of representing objects and processes. &lt;mark&gt;It involves defining problems; analysing problems; designing solutions; and developing, testing, and maintaining programs&lt;/mark&gt;. For the purposes of this document, the term computer studies refers to the study of computer science, meaning computer and algorithmic processes, including their principles, their hardware and software designs, their applications, and &lt;mark&gt;their impact on society&lt;/mark&gt;.&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Is that quote familiar?&lt;/p&gt;
&lt;p&gt;If you&#39;re a teacher in Ontario, it should be – it&#39;s from page 3 of the Ontario Computer Studies curriculum!&lt;/p&gt;
&lt;p&gt;That bit of rhetorical flourish exists in this article &lt;em&gt;with feeling&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I know that it is not easy to be a teacher, let alone a Computer Studies teacher.&lt;/p&gt;
&lt;p&gt;However, if all that we focus on are algorithms, code, and tools – if we address but don&#39;t emphasize the rest of the curriculum – we are doing our students a grave disservice.&lt;/p&gt;
&lt;p&gt;Over March Break this year, the Hackergal organization ran a terrific one-day workshop for teachers. The highlight was hearing from a panel of dynamic women working in the software industry:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet tw-align-center&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Today’s workshop &lt;a href=&quot;https://twitter.com/RyersonDMZ?ref_src=twsrc%5Etfw&quot;&gt;@RyersonDMZ&lt;/a&gt; is for the educators! This morning we will be hearing from a panel of inspiring women in tech to discuss what motivates them, equipping the next generation, &amp;amp; where the future of technology is heading! Let’s go @CIBCLiveLabs &lt;a href=&quot;https://twitter.com/cse_cst?ref_src=twsrc%5Etfw&quot;&gt;@cse_cst&lt;/a&gt; &lt;a href=&quot;https://twitter.com/riyakarumanchi?ref_src=twsrc%5Etfw&quot;&gt;@riyakarumanchi&lt;/a&gt;! &lt;a href=&quot;https://t.co/dQ0AEvTesA&quot;&gt;pic.twitter.com/dQ0AEvTesA&lt;/a&gt;&lt;/p&gt;&amp;mdash; Hackergal (@thehackergals) &lt;a href=&quot;https://twitter.com/thehackergals/status/1105809496931254273?ref_src=twsrc%5Etfw&quot;&gt;March 13, 2019&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;One common theme that emerged from the comments of the panelists was that they all started in the field of computer studies after high school&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:4&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Why was that? The specific examples varied, of course, but the gist? Computer studies classes in their schools focused nearly entirely on writing code, and there was little to no emphasis on the idea that computer studies is ultimately about &lt;em&gt;talking to people to identify problems and finding ways to solve those problems using technology&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Look, we know Apple has an excellent marketing team – but this video nails it:&lt;/p&gt;
&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://player.vimeo.com/video/173099570&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; title=&quot;vimeo video&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
 &lt;/div&gt;
&lt;p&gt;At my school, I am working to build a three-year computer studies &lt;em&gt;program&lt;/em&gt; that provides the full experience of problem solving and software development. I want students to graduate having published meaningful applications with a &lt;a href=&quot;https://github.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;portfolio of code&lt;/a&gt; they can use when speaking to prospective future clients or employers.&lt;/p&gt;
&lt;p&gt;So, in grade 10 this past year, we started early, working deliberately to improve our skill in offering an effective critique of each others&#39; work.&lt;/p&gt;
&lt;p&gt;Ron Berger&#39;s book, &lt;a href=&quot;https://www.heinemann.com/products/e00596.aspx&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;An Ethic of Excellence&lt;/a&gt;, is well worth your time – a brief but powerful text on how to guide students in creating meaningful, high-quality products.&lt;/p&gt;
&lt;p&gt;I like to use this video, featuring Ron, to introduce effective critique to my students:&lt;/p&gt;
&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://player.vimeo.com/video/38247060&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; title=&quot;vimeo video&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
 &lt;/div&gt;
&lt;p&gt;Eyes roll when my students see the age of the children in the video, but they are wowed by the end.&lt;/p&gt;
&lt;p&gt;As the year progressed, we practiced running usability trials for software that my students had authored, of the sort described here:&lt;/p&gt;
&lt;div style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin-bottom: 20px;&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/0YL0xoSmyZI&quot; style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&quot; allowfullscreen=&quot;&quot; title=&quot;YouTube Video&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;I make a point of building the opportunity for feedback and revision into the timeline of a task. This figure is instructive:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/steps-in-the-design-process-technological-education.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A diagram illustration steps in the design process.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;The design process is described in the preamble to the Ontario Technological Education curriculum.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here is one example of &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/iterative-product-design-and-implementation_-_rubric.pdf&quot;&gt;the outline and rubric for a task in Introduction to Computer Studies&lt;/a&gt;. This was filled out incrementally for every student as they submitted each required deliverable.&lt;/p&gt;
&lt;p&gt;That rubric may look a little different than you&#39;re used to – I am not fond of the traditional four-column rubric. I recommend taking a look at &lt;a href=&quot;https://twitter.com/siriusnerd&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;John Rampelt&lt;/a&gt;&#39;s deep dive into &lt;a href=&quot;https://docs.google.com/presentation/d/1fQlAkyRLmwtqvTrhmBgCW2DMC-eSeE0j6sP5EdjM_Go/edit#slide=id.g35f391192_00&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;single-point rubrics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After gaining confidence with software tools like &lt;a href=&quot;http://www.alice.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Alice&lt;/a&gt; and &lt;a href=&quot;https://thunkable.com/#/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Thunkable&lt;/a&gt;, and giving and receiving effective feedback first within our own class, then with students in other classes at LCS, I felt that my grade 10 students were ready to work within our local community.&lt;/p&gt;
&lt;p&gt;Through a collabration with two amazing teachers at a nearby elementary school, each my grade 10 students were tasked with being a contractor for a group of two to three grade 4 students. Based on requirements provided by the younger students, students in my class would design, prototype, and deliver a custom educational application.&lt;/p&gt;
&lt;p&gt;My students visited the grade 4 classes a total of four times to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Meet their clients and document their requirements.&lt;/li&gt;
&lt;li&gt;Present a paper prototype and receive feedback on their design.&lt;/li&gt;
&lt;li&gt;Present a functioning, but incomplete, software prototype, and receive feedback on their work to date.&lt;/li&gt;
&lt;li&gt;Deliver the final application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each visit lasted about forty-five minutes, and was spaced approximately two weeks apart on the calendar.&lt;/p&gt;
&lt;p&gt;The younger students asked for a wide variety of applications, including ideas like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a game that makes learning the Cartesian co-ordinate system fun&lt;/li&gt;
&lt;li&gt;a narrative where aliens landed and the student must find a way to prevent their family from being abducted&lt;/li&gt;
&lt;li&gt;an interactive hockey game, where correctly answering occasional math facts gave each player greater speed and dexterity when moving the puck&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;csp&quot;&gt;Here are some photos from our visits to the elementary school:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/example-1.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A grade four student operates a computer while a grade ten student looks on.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;An older student looks on while the younger student provides usability feedback. Photo by Will Callaghan.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/example-2.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Two grade four students manipulate an iPhone while a grade ten points out some functionality.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;Thunkable allowed my students to produce apps that ran on mobile devices for the younger students. Photo by Will Callaghan.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/example-3.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Two younger students listen while an older students explains some code running on a computer.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;An LCS student explains how some of the code he wrote works. Photo by Will Callaghan.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/example-4.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A teacher observes two younger students trying out a hockey game written by an LCS student.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;Good humour while a prototype of an interactive hockey game is demonstrated. Photo by Will Callaghan.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The hope was that by engaging with an external audience in a fairly authentic manner, my students would be motivated intrinsically to do their very best for this culminating task in the course.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;video width=&quot;568&quot; height=&quot;&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/mario-treasure-hunt.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Mario Treasure Hunt&lt;/h4&gt;
		&lt;p&gt;The completed version of the game that teaches Cartesian co-ordinates through play.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;What was the response like from my Grade 10 students?&lt;/p&gt;
&lt;p&gt;Here are some comments offered through an anonymous end-of-year survey:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This culminating task was more meaningful because it was more interesting and realistic. I felt like I was doing a real job and I loved working with the kids.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another offered:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For me, this culminating task was more meaningful, because I got to actually talk to people and it felt like I was really communicating with a user. Being with kids who have a lot of ideas was also helpful because then I could make my game more specific.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There were other similar responses.&lt;/p&gt;
&lt;p&gt;100% of my students felt a similar culminating task should run in this course next year.&lt;/p&gt;
&lt;p&gt;All of this makes it clear to me that how we &lt;em&gt;deploy&lt;/em&gt; our courses – how we ask our students to demonstrate their mastery of expectations – matters a lot.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As described in &lt;a href=&quot;https://99percentinvisible.org/episode/invisible-women&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the episode of 99% Invisible&lt;/a&gt;, it was not the benefits to residents of Karlskoga, or the town&#39;s bottom line, that was the point.&lt;/p&gt;
&lt;p&gt;It&#39;s that well-intentioned city planners actually &lt;em&gt;forgot to remember that women exist&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This would never have happened were there equitable gender representation in the city planner&#39;s office.&lt;/p&gt;
&lt;p&gt;The podcast episode describes several other examples of real harm that has come to women due to design that neglects to consider fifty percent of our planet&#39;s population.&lt;/p&gt;
&lt;p&gt;We cannot let the same thing happen in the software industry.&lt;/p&gt;
&lt;p&gt;As teachers, we have a moral imperative to do everything we can to make our computer studies classes welcoming to young women and to other under-represented groups.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;Talking about historical gender balance in my Computer Studies classes is complicated by the fact that while I have been a teacher at co-ed schools, I have also taught at an all-girls and an all-boys school. In Canada, some might call that a hat trick.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;Cheryan, Sapna, Benjamin J. Drury, and Marissa Vichayapai. “Enduring Influence of Stereotypical Computer Science Role Models on Women’s Academic Aspirations.” Psychology of Women Quarterly 37, no. 1 (March 2013): 72–79. doi:10.1177&amp;sol;0361684312459328.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:2&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;&lt;em&gt;The Ontario Curriculum, Grades 10 to 12, Computer Studies (Revised)&lt;/em&gt; (Toronto:  Ministry of Education, 2008), 3.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:3&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;Except Riya Karumanchi, who is still &lt;em&gt;in&lt;/em&gt; high school – but she is a pretty amazing special case.&lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:4&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt; 
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//teaching/snow-clearing-and-computer-studies-enrolment/" />
        </entry>
    
    
        <entry>
            <title>
                Integrate Coding in Mathematics using Python, Jupyter Notebooks, and Google Colab
                
            </title>
            <updated>2024-08-15T11:22:00.000Z</updated>
            <id>https://russellgordon.dev//teaching/integrate-coding-in-mathematics-using-python-jupyter-notebooks-and-google-colab/</id>
            <content type="html">
                &lt;h2 id=&quot;agenda&quot; tabindex=&quot;-1&quot;&gt;Agenda&lt;/h2&gt;
&lt;p&gt;For this session, here is the plan:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Timing&lt;/th&gt;
&lt;th&gt;Goals&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;td&gt;Introduction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 minutes&lt;/td&gt;
&lt;td&gt;Try out some notebooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;td&gt;Pair, share, questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;30 minutes&lt;/td&gt;
&lt;td&gt;Begin authoring a notebook of your own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;td&gt;Wrap-up&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;How can we meaningfully integrate coding into mathematics classes, and allow students to make their thinking visible?&lt;/p&gt;
&lt;p&gt;From the &lt;a href=&quot;https://www.dcp.edu.gov.on.ca/en/curriculum/secondary-mathematics/courses/mth1w/elements-of-the-grade-9-mathematics-course#mathematical-processes&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;MTH1W curriculum&lt;/a&gt;, regarding the selection of tools and strategies:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All students should be encouraged to select and use tools to illustrate mathematical ideas. Students come to understand that making their own representations is a powerful means of building understanding and of explaining their thinking to others. Using tools supports students as they:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;identify patterns and relationships;&lt;/li&gt;
&lt;li&gt;make connections between mathematical concepts and between concrete and abstract representations;&lt;/li&gt;
&lt;li&gt;test, revise, and confirm their reasoning;&lt;/li&gt;
&lt;li&gt;remember how they solved a problem;&lt;/li&gt;
&lt;li&gt;communicate their reasoning to others...&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The combination of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;a href=&quot;https://www.python.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Python programming language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the &lt;a href=&quot;https://jupyter.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Jupyter notebooks&lt;/a&gt; file format&lt;/li&gt;
&lt;li&gt;the &lt;a href=&quot;https://colab.research.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Google Colab environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;... allows students to share their approach to solving a problem and permits teachers to facilitate all of this with a minimum of fuss and bother.&lt;/p&gt;
&lt;p&gt;In time, students come to see coding not just as something that is done in addition to mathematics but as a viable tool for exploring mathematical relationships and for problem-solving.&lt;/p&gt;
&lt;h2 id=&quot;building-blocks-and-license&quot; tabindex=&quot;-1&quot;&gt;Building Blocks and License&lt;/h2&gt;
&lt;p&gt;For the the 2023-24 school year, a part of my role at &lt;a href=&quot;https://www.lcs.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Lakefield College School&lt;/a&gt; involved supporting my colleagues in the Mathematics department as they worked to meaningfully integrate coding into MTH1W.&lt;/p&gt;
&lt;p&gt;I started by consulting the work of &lt;a href=&quot;https://x.com/grant_hutchison&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Grant Hutchison&lt;/a&gt; and the &lt;a href=&quot;https://acse.net/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Association of Computer Studies Educators&lt;/a&gt; at the &lt;a href=&quot;https://acse.net/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Coding Integration&lt;/a&gt; website.&lt;/p&gt;
&lt;p&gt;Copyright for this post remains with me, Russell Gordon, but all of the Jupyter notebooks I will share, some of which are built upon work from the Coding Integration website, are published under &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the Creative Commons Attribution Non-Commercial Share-Alike 4.0 International license&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;practical-considerations&quot; tabindex=&quot;-1&quot;&gt;Practical Considerations&lt;/h2&gt;
&lt;p&gt;As a teacher I want use of a Jupyter notebook to be just as easy as distributing paper &lt;em&gt;to&lt;/em&gt; and collecting that paper &lt;em&gt;from&lt;/em&gt; my students. For students, use of the notebook should be as close to working on paper as possible, so as to reduce their cognitive load.&lt;/p&gt;
&lt;p&gt;Using &lt;a href=&quot;https://drive.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Google Drive&lt;/a&gt; to author and store Jupyter notebooks, &lt;a href=&quot;https://classroom.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Google Classroom&lt;/a&gt; to distribute and collect notebooks from students, and &lt;a href=&quot;https://colab.research.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Google Colab&lt;/a&gt; to interact with a notebook, gets pretty close to the ease of working with paper.&lt;/p&gt;
&lt;p&gt;Even without &lt;a href=&quot;https://classroom.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Classroom&lt;/a&gt;, you can create and work with Google Colab documents in &lt;a href=&quot;https://drive.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Drive&lt;/a&gt; the same way you can with Sheets, Docs, or Slides documents:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-13%20at%203.32.45%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-13 at 3.32.45 PM.png|650&quot; width=&quot;650px&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]&lt;/p&gt;
&lt;p&gt;Depending on your school or school district settings, in order to create Google Colab documents from the menu shown above, you may need to ask your IT administrator to &lt;a href=&quot;https://workspace.google.com/u/1/marketplace/app/colaboratory/1014160490159&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;enable this extension&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-13%20at%203.35.37%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-13 at 3.35.37 PM.png|500&quot; width=&quot;500px&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Even without this extension installed, it is still possible to duplicate existing Colab documents you have added to your Google Drive.&lt;/p&gt;
&lt;p&gt;In fact, duplicating and editing existing Colab documents is my recommended approach to authoring an activity. More on this later in the session.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;/p&gt;
&lt;p&gt;Of course, not every school or school district permits use of &lt;a href=&quot;https://workspace.google.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Google Workspace&lt;/a&gt; tools.&lt;/p&gt;
&lt;p&gt;Python Notebooks can also be used &lt;a href=&quot;https://callysto.ca/#about&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;within the Callysto environment&lt;/a&gt;, and stored within a &lt;a href=&quot;https://github.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;GitHub&lt;/a&gt; repository. This requires more technical skills on the part of the teacher. The workflow for students to submit their work to you as the teacher will likely have a few more steps, as well.&lt;/p&gt;
&lt;p&gt;Addressing the use of Jupyter Notebooks within Callysto and GitHub goes beyond the scope of this session.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;try-out-a-notebook&quot; tabindex=&quot;-1&quot;&gt;Try Out a Notebook&lt;/h2&gt;
&lt;p&gt;Assuming that you have access to a Google account, either with a personal email address, or through your school or school board, jump in to the first Jupyter notebook that I authored for grade 9 students to work with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1VrdV8Ome1rXW8DxxulJ3gU3Oa_3jA6Pj?usp=share_link&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Balancing Equations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are not logged in to a Google account, after following that link, you will be able to  view but not save changes to the notebook. Be sure to sign in:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.38.31%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.38.31 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After signing in to a Google account, click the &lt;strong&gt;Changes will not be saved&lt;/strong&gt; link:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.45.15%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.45.15 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;... then choose &lt;strong&gt;Save a copy in Drive&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.51.03%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.51.03 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You may see a note from the &lt;strong&gt;Google Colab&lt;/strong&gt; team describing recent changes to the Colab environment – you can dismiss this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.54.45%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.54.45 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;At this point you are ready to begin navigating the document.&lt;/p&gt;
&lt;p&gt;Use the &lt;strong&gt;Table of Contents&lt;/strong&gt; to move around within the document without a lot of scrolling:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.56.18%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.56.18 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The vertical yellow marker identifies what section of the document you have most recently navigated to.&lt;/p&gt;
&lt;p&gt;This is a notebook designed for first use with students and coding in Grade 9 mathematics. By approaching a topic every student should have some familiarity with – solving equations – they can, at first, focus on the code they are writing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-09%20at%209.15.36%E2%80%AFAM.png&quot; alt=&quot;Screenshot 2024-08-09 at 9.15.36 AM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Beginning with the &lt;strong&gt;Questions for you to try&lt;/strong&gt; section, students are invited to write their own code, and balance equations independently:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://russellgordon.dev/img/user/Media/Screenshot%202024-08-08%20at%201.59.52%E2%80%AFPM.png&quot; alt=&quot;Screenshot 2024-08-08 at 1.59.52 PM.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Jupyter notebooks are a combination of &lt;em&gt;text blocks&lt;/em&gt; and &lt;em&gt;code blocks&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Code blocks must be run in order, from the top of a notebook to the bottom.&lt;/p&gt;
&lt;p&gt;Jupyter notebooks, like &lt;a href=&quot;https://posit.co/products/open-source/rstudio/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;R Studio&lt;/a&gt; documents, were designed to support &lt;a href=&quot;https://engineering.rappi.com/reproducible-data-science-and-why-it-matters-e4e62fd60b9a&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;reproducible data science&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;/p&gt;
&lt;p&gt;As an aside regarding reproducible data science, &lt;a href=&quot;https://www.russellgordon.ca/rsgc/r/Statistics_Project_-_Exemplar.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;here is an exemplar&lt;/a&gt; I made for the culminating project when I last taught MDM4U.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This heritage of support for reproducible data science in Jupyter notebooks allows students &lt;a href=&quot;https://pz.harvard.edu/resources/making-thinking-visible-how-to-promote-engagement-understanding-and-independence&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;to make their process and thinking visible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So... please take the time now to try out this first notebook.&lt;/p&gt;
&lt;p&gt;If you&#39;d prefer a more guided tour, here are a few short videos:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/997352520?h=1d2ec6cb65&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Getting Started with a Jupyter Notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/997352556?h=09b899e0d2&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Writing Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/997352634?h=f3f999b856&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Collecting Student Work&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additionally, please feel free to try out any of the notebooks included in the next section.&lt;/p&gt;
&lt;p&gt;I will circulate to answer individual questions as they arise.&lt;/p&gt;
&lt;h2 id=&quot;additional-notebooks&quot; tabindex=&quot;-1&quot;&gt;Additional Notebooks&lt;/h2&gt;
&lt;p&gt;Here are some other notebooks that you can open, duplicate, and try out now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1BQ0ozrV9OHr8lo0GPr8I8xihJU4kHwyv?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Introduction to Data Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/14XunJ64eXgXL3z1ZT-CfuDW8RRA9prn8?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Single-Variable Data Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1ffcORJjLZlAOZyZmLapBrd3XuxrObfIs?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Relations and Two-Variable Data Analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1FAwKrzbgHbGynh6ZUhai0Gq-wK822eTi?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Exploring Geometry, Iteration, Variables, and Functions&lt;/a&gt; 🚨&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1JTCHmt94knBbhdE68xU0M0Astm_UX5LQ?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Exploring Relations - Examples&lt;/a&gt; ✏️&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;/p&gt;
&lt;p&gt;🚨 This document is quite long, representing far more content than would be approachable in a single class for most if not all students. Later in this session, we will learn how to &amp;quot;slice and dice&amp;quot; a Jupyter notebook in Google Colab to easily create a revised version with less content.&lt;/p&gt;
&lt;p&gt;✏️ This document is not designed with a student audience in mind, but exists more as a set of examples for teachers to peruse and adapt as needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]&lt;/p&gt;
&lt;p&gt;Here is &lt;a href=&quot;https://drive.google.com/drive/folders/159jgczXQVXK05AE6lOUTOZQ_e3M-sT-P?usp=share_link&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a folder in Google Drive&lt;/a&gt; containing all of the notebooks, and their related resources.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;mid-session-questions&quot; tabindex=&quot;-1&quot;&gt;Mid-session Questions&lt;/h2&gt;
&lt;p&gt;The following questions came up during this session. As best as was possible, the questions and answers have been documented below. My thanks to Rob Gleeson for taking notes while questions were fielded during the session.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;When we ran the code inside various code cells, starting in the middle of a Jupyter notebook and then running code within cells above and below the one we started with, we got inconsistent results. Why did that happen?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code blocks must be run once each, in sequence, much like pages in a novel must be read in order so that the narrative makes sense.&lt;/li&gt;
&lt;li&gt;When code blocks are run out of the order they are presented in, output will change.&lt;/li&gt;
&lt;li&gt;Be sure to run code blocks in order from top to bottom within a notebook.
&lt;ul&gt;
&lt;li&gt;Students new to coding will encounter this issue too.&lt;/li&gt;
&lt;li&gt;When that occurs, it can be a good opportunity to discuss sequence as a key programming concept; this issue is connected to &lt;a href=&quot;https://assets-us-01.kc-usercontent.com/fbd574c4-da36-0066-a0c5-849ffb2de96e/3f76051d-897c-45f4-bc9b-86bc3934b6b9/The%20Ontario%20Curriculum%20-%20Mathematics%20Grade%209%20De-streamed%20Course%202021_with%20Teacher%20Supports.pdf#page=122&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;expectations within section C2 of the MTH1W curriculum&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If you need to clear the output of code blocks to reset a notebook, choose the menu sequence: &lt;strong&gt;Runtime &amp;gt; Disconnect and delete runtime&lt;/strong&gt; and then &lt;strong&gt;Edit &amp;gt; Clear all outputs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I noticed that algebraic expressions are always simplified within the &lt;a href=&quot;https://colab.research.google.com/drive/1VrdV8Ome1rXW8DxxulJ3gU3Oa_3jA6Pj?usp=share_link&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Balancing Equations&lt;/a&gt; notebook. Is there a way to turn that off?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are some limited ways to control whether expressions that involve a certain variable are simplified, but no straightforward way that I have found to disable simplification entirely.&lt;/li&gt;
&lt;li&gt;My current thoughts are to use the automatic simplification of expressions by the SymPy library as an opportunity to discuss the concept of equivalent algebraic expressions with students. This is a part of the &lt;a href=&quot;https://assets-us-01.kc-usercontent.com/fbd574c4-da36-0066-a0c5-849ffb2de96e/3f76051d-897c-45f4-bc9b-86bc3934b6b9/The%20Ontario%20Curriculum%20-%20Mathematics%20Grade%209%20De-streamed%20Course%202021_with%20Teacher%20Supports.pdf#page=112&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Ontario curriculum for MTH1W&lt;/a&gt; (expectation C1.3).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;authoring-notebooks&quot; tabindex=&quot;-1&quot;&gt;Authoring Notebooks&lt;/h2&gt;
&lt;p&gt;The easiest way to get started with authoring a notebook is to make a copy of an existing notebook, and then modify it to suit your needs.&lt;/p&gt;
&lt;p&gt;Here are a series of short videos explaining important concepts for authoring Jupyter notebooks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/998852229?h=1cbb0e799a&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Organizing a Notebook Using Headings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/998852282?h=49831cfda4&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Quickly Removing Portions of a Notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/998852339?h=08dda4e459&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Moving Cells From One Notebook to Another&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/998852369?h=44c33c7d0e&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Adding Images to a Notebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://player.vimeo.com/video/998852416?h=c1c53998eb&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Adding Text and Code Cells and Staying Organized&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;templates-for-students&quot; tabindex=&quot;-1&quot;&gt;Templates for Students&lt;/h2&gt;
&lt;p&gt;Referring to the &lt;a href=&quot;https://assets-us-01.kc-usercontent.com/fbd574c4-da36-0066-a0c5-849ffb2de96e/3f76051d-897c-45f4-bc9b-86bc3934b6b9/The%20Ontario%20Curriculum%20-%20Mathematics%20Grade%209%20De-streamed%20Course%202021_with%20Teacher%20Supports.pdf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;PDF version of the curriculum for MTH1W&lt;/a&gt;, the term &lt;em&gt;coding&lt;/em&gt; shows up 67 times. I will venture that the spirit of the new curriculum is to see coding become a another tool regularly used by students – not something that is &amp;quot;done&amp;quot; after one or two classes.&lt;/p&gt;
&lt;p&gt;To that end, we can provide students with templates for common tasks, or develop such templates collaboratively with our classes – after organically looking at how coding helps us to explore a given mathematical concept.&lt;/p&gt;
&lt;p&gt;After students become comfortable with using a Jupyter notebook in the Colab environment, they can reach for these templates as needed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/1mi1AROoGvdNCKdKcrL2lyiW-LurUCmLE?usp=sharing&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Single-Variable Data Analysis - Template&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://colab.research.google.com/drive/14VsGOvjQSLycu-tDDqAclc-IEwIKYBl0?usp=drive_link&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Two-Variable Data Analysis - Template&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CONSIDER]&lt;/p&gt;
&lt;p&gt;What other templates might be useful for us, as teachers, to create for our students to use?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;publishing-spreadsheets-as-a-data-source&quot; tabindex=&quot;-1&quot;&gt;Publishing Spreadsheets as a Data Source&lt;/h2&gt;
&lt;p&gt;When teaching students how to analyze one or two-variable data, it&#39;s ideal to make it as easy as possible for them to access that data.&lt;/p&gt;
&lt;p&gt;One option is to &lt;a href=&quot;https://player.vimeo.com/video/998676210?h=a97979805c&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;publish the spreadsheet as a CSV file&lt;/a&gt; via the user interface within a Google Sheet.&lt;/p&gt;
&lt;p&gt;Another option is to edit the spreadsheet URL directly.&lt;/p&gt;
&lt;p&gt;Given a link to a spreadsheet, such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://docs.google.com/spreadsheets/d/1E-iostgx4RiEajIu5DhVs-n6hXdQ1uPcLcWPFQc437s/edit?gid=0#gid=0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... replace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/edit?gid=0#gid=0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/export?format=csv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://docs.google.com/spreadsheets/d/1E-iostgx4RiEajIu5DhVs-n6hXdQ1uPcLcWPFQc437s/export?format=csv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then load the contents of the spreadsheet into a dataframe in a Jupyter notebook, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# Load the data from the spreadsheet
collected_data = pd.read_csv(&amp;quot;https://docs.google.com/spreadsheets/d/1E-iostgx4RiEajIu5DhVs-n6hXdQ1uPcLcWPFQc437s/export?format=csv&amp;quot;).dropna()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;try-authoring-your-own-notebook&quot; tabindex=&quot;-1&quot;&gt;Try Authoring Your Own Notebook&lt;/h2&gt;
&lt;p&gt;Take one of the notebooks shared earlier, and try revising or extending it, or author your own from scratch.&lt;/p&gt;
&lt;p&gt;I will circulate to help as needed.&lt;/p&gt;
&lt;p&gt;Optionally, submit your completed notebook &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSdnK27Kzed0Y8tdOdwhbbjYowlh_xLPcf1i_HWbdbWmxTBhXw/viewform&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;to this Google form&lt;/a&gt;. By doing so, you are giving permission for your notebook to be shared within this article and &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/4.0/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;published under the license described earlier&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;publishing-workflow&quot; tabindex=&quot;-1&quot;&gt;Publishing Workflow&lt;/h2&gt;
&lt;p&gt;If you are curious about how the materials for this session were published, that was the topic of &lt;a href=&quot;https://teaching.russellgordon.ca/cemc/sccst-2023/a-rapid-workflow-for-publishing-cs-teaching-materials/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;the session I ran last year&lt;/a&gt;, in August 2023, at the &lt;a href=&quot;https://cemc.uwaterloo.ca/events/csteachers.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;CEMC Summer Conference for Computer Studies Educators&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;author-background&quot; tabindex=&quot;-1&quot;&gt;Author Background&lt;/h2&gt;
&lt;p&gt;Before teaching, I worked in the software industry for four years as a developer and technical support specialist. After a year at &lt;a href=&quot;https://www.oise.utoronto.ca/home&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;OISE/UT&lt;/a&gt;, in 2006 I started teaching with a fall semester LTO at the &lt;a href=&quot;https://www.thespec.com/opinion/contributors/don-t-write-off-barton-secondary-school/article_5d4e0dff-5b27-5ec8-b7f8-c09739a71714.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;now-closed Barton Secondary School&lt;/a&gt; in Hamilton, Ontario. To conclude that school year I completed a spring semester LTO at &lt;a href=&quot;https://erindale.peelschools.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Erindale Secondary School&lt;/a&gt; in Mississauga.&lt;/p&gt;
&lt;p&gt;In 2007 I was fortunate to earn a permanent position at &lt;a href=&quot;https://northpark.peelschools.org/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;North Park Secondary School&lt;/a&gt; in Brampton where the existence of the &lt;a href=&quot;https://northpark.peelschools.org/international-business-and-technology&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;International Business and Technology Program&lt;/a&gt; allowed me to combine my background in technology with my love of teaching and learning. Across four years at North Park, I served for two years as the department head of the IBT program, taught a variety of mathematics classes, and grew computer science enrolment from 1 to 7 sections.&lt;/p&gt;
&lt;p&gt;By 2011, my young family and I had moved to downtown Toronto. A desire to live in an urban environment without owning a car, some &lt;a href=&quot;https://www.thestar.com/politics/provincial/does-ontario-s-regulation-274-help-or-harm-students/article_2a56ba3b-6a01-56a7-ab3b-67434c290ce5.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;changes to hiring rules in public school boards&lt;/a&gt;, and the need to support my family without the uncertainty of work as a supply teacher, led me to pursue employment within independent schools. For three years, I worked at the &lt;a href=&quot;https://www.bss.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Bishop Strachan School&lt;/a&gt; in a variety of roles as a teacher of mathematics and computer science and as a technology integrator. A move to &lt;a href=&quot;https://www.rsgc.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Royal St. George&#39;s College&lt;/a&gt; in 2014 allowed for a new challenge – working within an all-boys environment after having taught at an all-girls school.&lt;/p&gt;
&lt;p&gt;Toronto is a terrific city in many ways. By 2017, however, my family and I were ready for a change and, frankly, for a more affordable place to live. I am grateful to be a part of the community of teachers and learners at &lt;a href=&quot;https://www.lcs.on.ca/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Lakefield College School&lt;/a&gt;, where I currently &lt;a href=&quot;https://issuu.com/lakefieldcs/docs/lcsgrovenews_issu/40&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;teach computer science&lt;/a&gt; to students &lt;a href=&quot;https://www.genderspectrum.org/about&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;across the gender spectrum&lt;/a&gt; and work with colleagues, where I can, to help advance pedagogy and the appropriate use of technology.&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//teaching/integrate-coding-in-mathematics-using-python-jupyter-notebooks-and-google-colab/" />
        </entry>
    
    
        <entry>
            <title>
                Building Computer Studies Classes for Student Agency
                
            </title>
            <updated>2020-08-20T22:30:32.000Z</updated>
            <id>https://russellgordon.dev//teaching/building-computer-studies-classes-for-student-agency/</id>
            <content type="html">
                &lt;p&gt;No teacher knows quite what to expect in this coming school year.&lt;/p&gt;
&lt;p&gt;What teachers do know is that the intrinsic motivation of our students is key to a positive outcome.&lt;/p&gt;
&lt;p&gt;Whether we are learning in-person or remotely a student has a finite number of hours to dedicate to schoolwork.&lt;/p&gt;
&lt;p&gt;And naturally we want computer studies to come first. 😇&lt;/p&gt;
&lt;p&gt;How do we make that happen?&lt;/p&gt;
&lt;h2 id=&quot;student-agency&quot; tabindex=&quot;-1&quot;&gt;Student Agency&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Writing software is a creative endeavour.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since we teach computer studies it&#39;s a fair bet that we&#39;ve all experienced that feeling of being &amp;quot;in the zone&amp;quot; while coding and the rush that comes when a goal is reached or a challenging problem solved.&lt;/p&gt;
&lt;p&gt;In speaking with colleagues who teach visual art I&#39;ve come to the conclusion that the emotional experience of writing software is not all that different from an artist working on a piece.&lt;/p&gt;
&lt;p&gt;There is absolutely a place for specifications, one-size-fits-all assignments, and asking students to complete a defined task to learn a technique or evaluate a particular skillset.&lt;/p&gt;
&lt;p&gt;If that is, however, the majority of a student&#39;s experience with our class – while their time with us may be occasionally &lt;em&gt;interesting&lt;/em&gt; – it is unlikely to have felt terribly creative.&lt;/p&gt;
&lt;p&gt;It must be our goal for students to finish our course feeling like an artist.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How many artists are told what to make?&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;start-with-conversations&quot; tabindex=&quot;-1&quot;&gt;Start With Conversations&lt;/h2&gt;
&lt;p&gt;What do your students do for fun?&lt;/p&gt;
&lt;p&gt;Is it chess?&lt;/p&gt;
&lt;p&gt;Drawing?&lt;/p&gt;
&lt;p&gt;Going for a run?&lt;/p&gt;
&lt;p&gt;What do your students worry about?&lt;/p&gt;
&lt;p&gt;What problems do they want to solve in this world?&lt;/p&gt;
&lt;p&gt;Facilitate a discussion about this.&lt;/p&gt;
&lt;p&gt;Once students have warmed up to it, ask them write about their interests.&lt;/p&gt;
&lt;p&gt;Use their responses as your guidebook to each student for their time in your course.&lt;/p&gt;
&lt;h2 id=&quot;a-name-sharing-a-foster-a-culture-of-sharing&quot; tabindex=&quot;-1&quot;&gt;&lt;a name=&quot;sharing&quot;&gt;&lt;/a&gt;Foster a Culture of Sharing&lt;/h2&gt;
&lt;p&gt;How often have you achieved a goal when writing a program and then immediately sought out your best friend, partner, or child to show them your brilliance?&lt;/p&gt;
&lt;p&gt;How often have you been a bit disappointed when they didn&#39;t seem quite as impressed as they &lt;em&gt;really honestly should be&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Students &lt;em&gt;want&lt;/em&gt; to share what they&#39;ve made.&lt;/p&gt;
&lt;p&gt;If they can explain it with enough clarity that someone else might be able to at least appreciate the effort involved – then it&#39;s a fair bet that the student really understands what they&#39;ve done&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s our job to make that a regular part of class – something that students look forward to both as the person sharing or as the audience.&lt;/p&gt;
&lt;p&gt;Have an extrovert on your hands? Let them share a success live in class.&lt;/p&gt;
&lt;p&gt;Does a student worry about missing a detail or stumbling over words when speaking in front of others? Have them record a screencast demoing their work and explaining a key piece of logic.&lt;/p&gt;
&lt;p&gt;Might someone not like how they sound on video? Ask them to write a blog post instead, and give other students the chance to read their work in advance of a class discussion.&lt;/p&gt;
&lt;p&gt;Reserve time in each class for this exchange of ideas, with two or three students sharing each time you meet. Set up a regular schedule so students know when it&#39;s their turn.&lt;/p&gt;
&lt;p&gt;This kind of conversation is not just for end products. It&#39;s a work in progress? Great! You&#39;re stuck with a syntax error or a logical error? No worries! Especially reinforce for your students that sharing challenges, and strategies employed in an attempt to solve the problem, are often more valuable fodder for discussion.&lt;/p&gt;
&lt;p&gt;We want our students to feel like they are in cahoots together. That they can freely lean over, or speak up, and help someone else out.&lt;/p&gt;
&lt;p&gt;Our students will be largely working toward their individual&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; goals in the course and it&#39;s that &lt;em&gt;process of creation&lt;/em&gt; throughout the year, &lt;em&gt;as much or more&lt;/em&gt; than the end product, that must form the bulk of evidence used to determine a student&#39;s final grade.&lt;/p&gt;
&lt;p&gt;Since students are each working on a differentiated product, and they&#39;ll understand that they must be able to explain their work, we have everything to gain by encouraging a healthy collaborative environment in our classes.&lt;/p&gt;
&lt;h2 id=&quot;evaluate-mastery-of-learning-goals&quot; tabindex=&quot;-1&quot;&gt;Evaluate Mastery of Learning Goals&lt;/h2&gt;
&lt;p&gt;My second semester as a teacher was in the Mathematics department at Erindale Secondary School in Mississauga in the winter and spring of 2007.&lt;/p&gt;
&lt;p&gt;I will never forget a meeting where the department head, John Flanagan, had one activity on the agenda: take a photocopy of the same student&#39;s responses for a unit test, take a copy of the solutions, go away and grade it, and then come back in twenty minutes to share and discuss the results.&lt;/p&gt;
&lt;p&gt;Across the ten or so colleagues in that department we had a range of percentage grades for that test from 70% to 90%.&lt;/p&gt;
&lt;p&gt;As a young teacher just starting out, that was an eye-opening experience.&lt;/p&gt;
&lt;p&gt;Most teachers will, at least in private, acknowledge that numeric grades convey a false sense of precision.&lt;/p&gt;
&lt;p&gt;Can you honestly tell someone the difference between a student who has earned 96% versus one who has earned 97% in your course at the end of the year?&lt;/p&gt;
&lt;p&gt;Now can you do that for some subset of time and curriculum expectations?&lt;/p&gt;
&lt;p&gt;Contrast that to a binary evaluation – yes or no – of whether a student has met an expectation. Most teachers feel comfortable with this.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Teacher:&lt;/strong&gt; Can you decompose a problem and apply that in code?&lt;br /&gt;
&lt;strong&gt;Student:&lt;/strong&gt; Sure I can – see here where I&#39;ve used functions, and in this other program where I wrote a class – see, I reused that from an earlier program I wrote.&lt;br /&gt;
&lt;strong&gt;Teacher:&lt;/strong&gt; OK, decomposing a problem... ✅&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I grudgingly issue a percentage grade when required to for reporting deadlines at my school, but only after I&#39;ve spoken to the student one-on-one, they&#39;ve shown me their portfolio containing evidence of mastery for various learning goals, we&#39;ve talked about what they&#39;ve &lt;a href=&quot;https://russellgordon.dev/#sharing&quot;&gt;been able to cogently explain&lt;/a&gt;, and the student has made a proposal for what grade they feel they have earned. Far more often than not, students are realistic about where they stand.&lt;/p&gt;
&lt;h2 id=&quot;time-out&quot; tabindex=&quot;-1&quot;&gt;Time Out&lt;/h2&gt;
&lt;p&gt;Right about now, you may be feeling like this is a nice picture being painted, but &lt;em&gt;get real&lt;/em&gt;. This sounds like a tall order in a normal year. During a pandemic? That&#39;s madness.&lt;/p&gt;
&lt;p&gt;Well, that&#39;s correct – we are in a pandemic.&lt;/p&gt;
&lt;p&gt;Can you count on in-person instruction for this entire school year? No, of course not.&lt;/p&gt;
&lt;p&gt;Any evaluation plan dependent upon seeing a student do something within a defined period of time in your class is a non-starter.&lt;/p&gt;
&lt;p&gt;Any evaluation plan centred upon all of your students solving the same set of defined problems with the same expected output will be fraught with the kinds of challenges none of us became a teacher to spend time upon.&lt;/p&gt;
&lt;p&gt;Perhaps you are a dogged personality and insist on trying to replicate the types of evaluation you&#39;ve used for in-person learning with remote learning.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;In class or at home, I&#39;ll demand rigor by requiring all students to complete the same tasks on the same timeline.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;d encourage you to consider whom that stance advantages and disadvantages. If your students are learning from home, do they all have equal access to a quiet space to learn? The same high-speed Internet? A reliable device? A parent who is not sick with COVID-19? What is it that your highly rigorous evaluation plan is evaluating? What a student knows or how much privilege they have? Do you really want to get into the privacy and ethics morass of &lt;a href=&quot;https://www.technologyreview.com/2020/08/07/1006132/software-algorithms-proctoring-online-tests-ai-ethics/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;testing-at-home software&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;I&#39;m painting a caricature, of course. I doubt that any teacher&#39;s thinking is so rigid.&lt;/p&gt;
&lt;p&gt;If we are to have students:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;make a decision, at the outset, about what they want to build in your course&lt;/li&gt;
&lt;li&gt;gain the skills required to reach their goal&lt;/li&gt;
&lt;li&gt;be able to explain concepts to others&lt;/li&gt;
&lt;li&gt;build a portfolio of evidence differentiated from that of their peers&lt;/li&gt;
&lt;li&gt;understand how they&#39;ve progressed against a clear set of learning goals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;... what does that look like, on a practical level?&lt;/p&gt;
&lt;h2 id=&quot;start-at-the-beginning&quot; tabindex=&quot;-1&quot;&gt;Start at the Beginning&lt;/h2&gt;
&lt;p&gt;Not with &amp;quot;Hello world.&amp;quot;&lt;/p&gt;
&lt;p&gt;Especially early on in my career I made the mistake of overemphasizing programming skills.&lt;/p&gt;
&lt;p&gt;Computer studies is far more than that. Says who? Says the Ontario curriculum.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/critical-areas.png&quot; loading=&quot;lazy&quot; alt=&quot;A table describing that &#39;effective learning in all aspects of computer studies depends on the  development of knowledge and skills in the following four areas.&#39; Those four areas are: 1. Software development (including project management and software engineering principles) 2. Algorithms and data structures 3. Program correctness and efficiency 4. Professional and ethical responsibility&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;What does effective computer studies learning look like?&lt;/h4&gt;
	&lt;p&gt;It&#39;s not just programming. From page 4 of the &lt;a href=&quot;http://edu.gov.on.ca/eng/curriculum/secondary/computer10to12_2008.pdf&quot;&gt;The Ontario Curriculum, Grades 10 to 12, Computer Studies, 2008 (revised)&lt;/a&gt;.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If we want a broad range of students to be engaged with computer studies, if we want to see &lt;a href=&quot;https://russellgordon.dev/teaching/snow-clearing-and-computer-studies-enrolment&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;greater enrolment from under-represented groups&lt;/a&gt;, we must be true to the curriculum.&lt;/p&gt;
&lt;p&gt;Begin with the design cycle.&lt;/p&gt;
&lt;p&gt;That student who loves chess? Help them arrange a video interview with a local chess club and find out what their members think a learn-to-play-chess app should include.&lt;/p&gt;
&lt;p&gt;That student who loves to run? Set them up with athletes in a local running club to find out what functionality they&#39;d like to see in their ideal intervals training app.&lt;/p&gt;
&lt;p&gt;Maybe your students need a bit more structure – maybe they can&#39;t put their finger on a problem they want to solve.&lt;/p&gt;
&lt;p&gt;In that case, consider speaking to an elementary teacher in your board. Younger students become the clients – your students are the developers. Use class time to set up video interviews between the two classes. Your students write educational games to the specifications of the elementary school students.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Your students cannot be their own audience.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;They need to experience what it&#39;s like to speak with a potential end-user.&lt;/p&gt;
&lt;p&gt;They need to know what they are shooting for when, inevitably, they get frustrated with syntax in your class, or you are tackling a particularly challenging coding concept.&lt;/p&gt;
&lt;p&gt;When students know they have an authentic learning opportunity, I&#39;m not exaggerating, it&#39;s like magic. They will find &lt;em&gt;you&lt;/em&gt; to ask what can be done next. Project management becomes something students &lt;em&gt;want&lt;/em&gt; to learn, because it&#39;s helping them achieve a goal they care about.&lt;/p&gt;
&lt;h2 id=&quot;use-source-control&quot; tabindex=&quot;-1&quot;&gt;Use Source Control&lt;/h2&gt;
&lt;p&gt;Source control, and &lt;code&gt;git&lt;/code&gt; in particular, have &lt;a href=&quot;https://xkcd.com/1597/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;a questionable reputation for usability&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In truth, basic usage is not that hard. There is a &lt;a href=&quot;https://desktop.github.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;graphical client&lt;/a&gt;. And &lt;a href=&quot;https://github.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;GitHub&lt;/a&gt; has a lot of &lt;a href=&quot;https://github.com/features/project-management&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;nice project management features&lt;/a&gt; built in.&lt;/p&gt;
&lt;p&gt;You can explore the &lt;a href=&quot;https://education.github.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;GitHub Education offering&lt;/a&gt;, or you can keep it simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;students create a repository for each program they write&lt;/li&gt;
&lt;li&gt;repositories are public&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:3&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;commit frequently&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With source control, you know exactly what code a student wrote and when.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/commit-history-excerpt.png&quot; loading=&quot;lazy&quot; alt=&quot;A table showing a list of commits to a student&#39;s repository that took place over several weeks.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Commit history for a student&#39;s culminating task&lt;/h4&gt;
	&lt;p&gt;When a student commited code is clear. Coaching students to use descriptive commit messages is an ongoing task. Code changes can be seen by selecting the hash link (in blue) for a given commit.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Teachers know how a program is written – it&#39;s organic, bit by bit – and it most definitely doesn&#39;t happen with a single commit. Tracing the evolution of a student&#39;s work, from an academic honesty point of view, is straightforward&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:4&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Use of GitHub means students can easily provide evidence for their portfolios – including &lt;a href=&quot;https://mariusschulz.com/articles/sharing-line-highlights-in-github-files&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;specific line numbers of a given file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Source control makes it a snap for students to identify and retreat from situations where their code has stopped working. Have a problem? Do a diff on your code to quickly see what&#39;s changed since the most recent commit. Can&#39;t figure it out? Revert state to your last commit and try again.&lt;/p&gt;
&lt;p&gt;It&#39;s possible to write an entire series of articles on using source control in the classroom.&lt;/p&gt;
&lt;p&gt;The short version is – basic usage is straightforward – and it&#39;s essential if you wish to differentiate your class and allow students to be specific when providing evidence of having met learning goals.&lt;/p&gt;
&lt;h2 id=&quot;use-portfolios&quot; tabindex=&quot;-1&quot;&gt;Use Portfolios&lt;/h2&gt;
&lt;p&gt;Artists create a portfolio of work, even as they learn. Students cannot apply to post-secondary programs in the arts without a portfolio.&lt;/p&gt;
&lt;p&gt;Increasingly, summer employers in the technology sector want to see what a student has on their GitHub profile as evidence of what they can do.&lt;/p&gt;
&lt;p&gt;Students looking to differentiate themselves from the pack in university applications can use their portfolio for that purpose, too.&lt;/p&gt;
&lt;p&gt;When populating a portfolio becomes a regular part of your class (and it really needs to be a part of the daily process) students &lt;em&gt;will learn&lt;/em&gt; the expectations. They tag evidence with the expectation they believe it fulfills. This becomes second nature. The onus is on students to show you what they know – it&#39;s not feasible for you, the teacher, to seek out evidence on your students&#39; behalf.&lt;/p&gt;
&lt;p&gt;Ideally you have access to a tool that makes this process sustainable.&lt;/p&gt;
&lt;p&gt;That might be something fancy – a dedicated tool like &lt;a href=&quot;https://spacesedu.com/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Spaces&lt;/a&gt; or something similar.&lt;/p&gt;
&lt;p&gt;Or it can be very basic. Last year, I had students maintain a Google Doc, submitted through Google Classroom, using a template I provided at the start of each portion of our course.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/portfolio-excerpt.png&quot; loading=&quot;lazy&quot; alt=&quot;An excerpt from a student portfolio, showing a narrative text and links to source code snippets on GitHub.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;An excerpt from a student portfolio&lt;/h4&gt;
	&lt;p&gt;A point form narrative with links to snippets of source code is maintained throughout the year and forms the basis of regular 1:1 meetings with students to discuss grades at reporting time.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;be-the-guide-at-the-side-not-the-sage-on-the-stage&quot; tabindex=&quot;-1&quot;&gt;Be the Guide at the Side, Not the Sage on the Stage&lt;/h2&gt;
&lt;p&gt;Class time is valuable.&lt;/p&gt;
&lt;p&gt;In-person class time, this year, is precious.&lt;/p&gt;
&lt;p&gt;Do you need to teach a specific concept? Explain a procedure?&lt;/p&gt;
&lt;p&gt;Don&#39;t do that live to the whole class. Especially if you are teaching remotely.&lt;/p&gt;
&lt;p&gt;Convey specific skills or concepts by video. Record your own if you have to, but work now to build a stable of resources you can refer students to.&lt;/p&gt;
&lt;p&gt;Use synchronous class time, whether in-person or remote, for follow-up and discussion. For check-ins, for paired programming, for &lt;em&gt;anything other than students listening to you talk at them&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Timelines for when a proportion of learning goals need to be met, or when specific learning goals need to be met, must be clear to students.&lt;/p&gt;
&lt;p&gt;Big-picture thinking and identifying in advance what resources will help your students with each learning goal will form a large part of your planning.&lt;/p&gt;
&lt;p&gt;However, for most of the year, you are unlikely to have a specific lesson plan for each class. Your students will be working on different things each time you meet. What have they worked on? That will be documented in their portfolio – remember, students maintain these in each and every class. How do you know that&#39;s happening? You&#39;re reviewing their edits as a part of your planning time. Use software that makes that sustainable.&lt;/p&gt;
&lt;p&gt;Again, to be clear, we&#39;re absolutely not sitting back and reading Twitter while our students flail about.&lt;/p&gt;
&lt;p&gt;In class, you must be present for consultation, guidance, direction to new resources, or a timely piece of small-group direct instruction. You may be familiar with &lt;a href=&quot;https://www.freecodecamp.org/news/just-in-time-compilation-explained/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;just-in-time compilation&lt;/a&gt;. I tend to think of a differentiated classroom as &lt;em&gt;just-in-time teaching&lt;/em&gt;. Despite our best efforts, most students retain very little from full-group instruction. Find that moment when a student is curious, or frustrated – and know what to say, or where to direct them – that&#39;s when the learning will stick.&lt;/p&gt;
&lt;p&gt;Out of class, we corral useful materials. Provide asynchronous feedback. Record our own short, targeted videos. Build our own skillset. Reach out to parents – to share student successes – or, rarely in my experience – to talk about challenges you haven&#39;t been able to sort out through conversation with a student.&lt;/p&gt;
&lt;h2 id=&quot;spectrum-of-possibilities&quot; tabindex=&quot;-1&quot;&gt;Spectrum of Possibilities&lt;/h2&gt;
&lt;p&gt;Much of what I&#39;ve described probably &lt;a href=&quot;https://www.pblworks.org/what-is-pbl&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;sounds like project-based learning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I&#39;ve served up a &lt;a href=&quot;https://apps.apple.com/ca/app/chicago-lcs/id1488235985&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;main course with my students&lt;/a&gt; on occasion, I&#39;ve more often &lt;a href=&quot;https://www.pblworks.org/doing-project-vs-project-based-learning&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;dished out dessert&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That&#39;s an honest statement about my past practice. I &lt;a href=&quot;https://www.heinemann.com/products/e00596.aspx&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;know where I&#39;m headed&lt;/a&gt;, though.&lt;/p&gt;
&lt;p&gt;It takes time to figure this out. You don&#39;t have to start in the deep end.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.kiang.net/interests.html&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Douglas Kiang&lt;/a&gt; speaks about birdhouse projects. What&#39;s a birdhouse project? You know arts and crafts time at camp? Everyone is building the same birdhouse, but painting theirs in different colours than their peers? That&#39;s the idea, and it&#39;s honestly a great way to focus on a more specific subset of a curriculum. I&#39;ll take a course organized around birdhouse projects over one built on tests and one-size-fits-all assignments any day of the week.&lt;/p&gt;
&lt;p&gt;What are some practical examples?&lt;/p&gt;
&lt;p&gt;Talk with teachers in other subject areas. What are students learning in Physics class? Chemistry? Biology? Have your students earn credit in two courses at one time by building a program that models a concept from another subject area.&lt;/p&gt;
&lt;p&gt;Generative art is a &lt;a href=&quot;https://drive.google.com/file/d/0B9h469--G5OwOGVfVmUxZUQ5VzA/view&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;full of algorithms&lt;/a&gt; that contain a rich overlap between art, mathematics, and programming. &lt;a href=&quot;https://twitter.com/search?q=%23plottertwitter&amp;amp;src=typeahead_click&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Plotters bring generative art&lt;/a&gt; from the virtual realm to the physical.&lt;/p&gt;
&lt;p&gt;Generative art can be animated:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;video width=&quot;568&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/example-end-product.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Generative art built by a student&lt;/h4&gt;
		&lt;p&gt;This builds upon an algorithm outlined by &lt;a href=&quot;http://reas.com/&quot;&gt;Casey Reas&lt;/a&gt; that involves moving circles around a canvas based on when they are about to overlap. Opacity of lines is a function of the distance between the midpoints of circle. The hue of lines is controlled in part by the amplitude of the music being played.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Or static:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;img src=&quot;https://russellgordon.dev/img/user/Media/t-shirt-birdhouse-project.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Example of a t-shirt design being transferred using photo-sensitive ink.&quot; width=&quot;568&quot; /&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Making tees with photo-sensitive ink&lt;/h4&gt;
		&lt;p&gt;From a past Grade 10 Introduction to Computer Studies class. Students  demonstrate their understanding of sequence, selection, and iteration by making images that &lt;a href=&quot;https://www.youtube.com/watch?v=h-_j6BsJPOQ&quot;&gt;can be transferred to t-shirts&lt;/a&gt; using &lt;a href=&quot;http://www.inkodye.com/&quot;&gt;photosensitive ink&lt;/a&gt;.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;prioritize&quot; tabindex=&quot;-1&quot;&gt;Prioritize&lt;/h2&gt;
&lt;p&gt;Whatever you do with your students, this year, more than any other year, some things will fall by the wayside.&lt;/p&gt;
&lt;p&gt;Don&#39;t stress about this.&lt;/p&gt;
&lt;p&gt;Decide now what&#39;s an essential understanding.&lt;/p&gt;
&lt;p&gt;Then be flexible.&lt;/p&gt;
&lt;p&gt;Err on the side of being generous.&lt;/p&gt;
&lt;p&gt;Assume best intentions.&lt;/p&gt;
&lt;p&gt;What will students remember about your class?&lt;/p&gt;
&lt;p&gt;Afford students even just a little bit of agency, and you&#39;ll never look back.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;It &lt;em&gt;certainly&lt;/em&gt; sounds like such a student will have demonstrated that they can &lt;a href=&quot;http://edu.gov.on.ca/eng/curriculum/secondary/computer10to12_2008.pdf&quot;&gt;convey meaning through various forms (see page 16)&lt;/a&gt;. &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;Or group goals, in Grade 12 Computer Science. &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:2&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:3&quot;&gt;Most of what you evaluate is a differentiated task that students document in their portfolio, right? There is no need for secrecy. Encourage a culture of students learning from one another. &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:3&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:4&quot;&gt;Should that even become necessary. My experience is that when students are doing authentic, differentiated work, cheating becomes a non-issue. &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:4&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//teaching/building-computer-studies-classes-for-student-agency/" />
        </entry>
    
    
        <entry>
            <title>
                A Planning Spreadsheet With A Curriculum Coverage Heat Map
                
            </title>
            <updated>2019-08-25T22:30:32.000Z</updated>
            <id>https://russellgordon.dev//teaching/a-planning-spreadsheet-with-a-curriculum-coverage-heat-map/</id>
            <content type="html">
                &lt;p&gt;When planning out your course it’s helpful to be able to &lt;em&gt;see&lt;/em&gt; what parts of the curriculum are well-covered and what parts may need more attention.&lt;/p&gt;
&lt;p&gt;Department heads, school board representatives, or Ministry of Education inspectors will find a heat map like this useful, too.&lt;/p&gt;
&lt;p&gt;If you populate a planning spreadsheet as described in this article, you will have a heat map like this:&lt;/p&gt;
&lt;figure style=&quot;width: 487px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/heat-map.png&quot; loading=&quot;lazy&quot; alt=&quot;A heat map illustrating coverage of expectations based on planned lessons.&quot; width=&quot;487&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Curriculum Coverage Heat Map&lt;/h4&gt;
	&lt;p&gt;A point in time while planning out Grade 11 Functions. The heat maps makes it clear that financial applications needs a little attention.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Colour codes are as follows:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Color&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Red&lt;/td&gt;
&lt;td&gt;No coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yellow&lt;/td&gt;
&lt;td&gt;Addressed once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blue&lt;/td&gt;
&lt;td&gt;Addressed twice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Light green&lt;/td&gt;
&lt;td&gt;Addressed three times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dark green&lt;/td&gt;
&lt;td&gt;Addressed four times or greater&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;To generate the heat map, while planning out the sequence of your course, all that’s needed is to tag what you are doing in a lesson or activity with curriculum expectations.&lt;/p&gt;
&lt;p&gt;For example, with Grade 11 Functions a few years ago, a colleague and I built the course in a spiralling progression, using many small “threads” and attempting to revisit larger curriculum topics more than once in a given year. To keep track of the learning occurring, we tagged our plans using curriculum expectations. See the &lt;em&gt;Exp.&lt;/em&gt; columns at right below:&lt;/p&gt;
&lt;figure style=&quot;width: 780px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/outline.png&quot; loading=&quot;lazy&quot; alt=&quot;An outline page listing threads, lessons, and expectations met through each day of instruction.&quot; width=&quot;780&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;using-the-planning-spreadsheet-for-an-existing-course&quot; tabindex=&quot;-1&quot;&gt;Using the Planning Spreadsheet for an Existing Course&lt;/h2&gt;
&lt;p&gt;If you happen to teach any of the following Ontario courses then you are in luck. I&#39;ve already built versions of this planning spreadsheet against the expectations from each course below&lt;a id=&quot;existing-courses&quot;&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1byTg8V0vC1wvwpdw5x1-IWji8b3ku9fC3j7KwYkHgrc/copy&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;ICS2O - Grade 10 - Introduction to Computer Studies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1d3mZkAB7nGtsaLPmD0ngdRYgDKbED9W6DJNL0hJUpDA/copy&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;ICS3U - Grade 11 - Introduction to Computer Science&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1Qem-qf3RSsSXq9xhiZ3X2e8MbjAl9lIPdqanOtD1zms/copy&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;ICS4U - Grade 12 - Computer Science&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1fpLzsjFTqSGeXYq2OGRNkifjwTJHYASK2JMkvDCFiFo/copy&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;MPM2D - Grade 10 - Principles of Mathematics, Academic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1Vc8p7xLU_Ihxb9S-GqcPyNsGF9102tf7p1OkNrFGp6E/copy&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;MCR3U - Grade 11 - Functions, University Preparation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To use any of the spreadsheets above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Follow the link; you will be prompted to make a copy of the spreadsheet in your own Google account.&lt;/li&gt;
&lt;li&gt;Complete &lt;a href=&quot;https://russellgordon.dev/#find-and-replace&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;this one step&lt;/a&gt; so that links within your new copy of the spreadsheet connect to your own spreadsheet (and not the templates provided).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;adapting-the-spreadsheet-to-another-course&quot; tabindex=&quot;-1&quot;&gt;Adapting the Spreadsheet to Another Course&lt;/h2&gt;
&lt;p&gt;Adapting an existing spreadsheet like this to a new set of curriculum expectations is unquestionably a chore, but once it’s done, you can use it for a course over and over again, without having to go through this process.&lt;/p&gt;
&lt;p&gt;Some tips&lt;a id=&quot;tips&quot;&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the &lt;a href=&quot;https://duckduckgo.com/?q=business+studies+curriculum+ontario+filetype%3Apdf&amp;amp;t=hi&amp;amp;ia=web&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;PDF version of a course curriculum for reference&lt;/a&gt; if you wish, but the &lt;a href=&quot;https://duckduckgo.com/?q=business+studies+curriculum+ontario+filetype%3Atxt&amp;amp;t=hi&amp;amp;ia=web&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;text-only version for cutting and pasting&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;To navigate within a text-only document, use Command-F and search for a passage of text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get started with adapting the planning spreadsheet to a new course, make a copy of the spreadsheet for any of the &lt;a href=&quot;https://russellgordon.dev/#existing-courses&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;existing courses mentioned above&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;step-one-update-strands-and-overall-expectations&quot; tabindex=&quot;-1&quot;&gt;Step One: Update Strands and Overall Expectations&lt;/h3&gt;
&lt;p&gt;This tab consolidates course strands and overall (major) expectations. It is used for reference and as a destination for hyperlinks from within the planning spreadsheet.&lt;/p&gt;
&lt;figure style=&quot;width: 780px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/overall-expectations.png&quot; loading=&quot;lazy&quot; alt=&quot;Overall expectations for the course in question.&quot; width=&quot;780&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Open the curriculum documents for your course (see &lt;a href=&quot;https://russellgordon.dev/#tips&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;tips&lt;/a&gt; above) and begin cutting and pasting.&lt;/p&gt;
&lt;p&gt;Colour coding for each row is managed automatically based on the contents of the &lt;em&gt;Strand&lt;/em&gt; column.&lt;/p&gt;
&lt;h3 id=&quot;step-two-update-the-minor-expectations&quot; tabindex=&quot;-1&quot;&gt;Step Two: Update the Minor Expectations&lt;/h3&gt;
&lt;p&gt;This tab consolidates the minor expectations for a course. It is used for reference and as a destination for hyperlinks within the planning spreadsheet.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Link Key&lt;/em&gt; and &lt;em&gt;Link Value&lt;/em&gt; columns are used for generating automatic links from the &lt;em&gt;Outline&lt;/em&gt; sheet when you tag lesson plans with relevant curriculum expectations.&lt;/p&gt;
&lt;figure style=&quot;width: 780px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/minor-expectations.png&quot; loading=&quot;lazy&quot; alt=&quot;Minor expectations for the course in question.&quot; width=&quot;780&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;There are several sub-steps required to build out this part of the spreadsheet.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Cut and paste the minor expectations within each overall (major) expectation from the ministry curriculum document.&lt;/p&gt;
&lt;p&gt;As you go, be sure to retain accurate labeling/numbering of strand, major, and minor expectations. The &lt;em&gt;Link Key&lt;/em&gt; field will then be automatically populated.&lt;/p&gt;
&lt;p&gt;For example, say that you are looking at the first strand (A), from the first major expectation (1), and there are four minor expectations (1, 2, 3, 4). The progression would look like this:&lt;/p&gt;
&lt;figure style=&quot;width: 670px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/progression.png&quot; loading=&quot;lazy&quot; alt=&quot;Progression of minor expectations for the course in question.&quot; width=&quot;670&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notice that the &lt;em&gt;Major&lt;/em&gt; column contains hyperlinks. These connect back to the &lt;em&gt;Overall Expectations&lt;/em&gt; sheet. The first major expectation is cell C2 on that sheet. The second major expectation is cell C3, and so on. Cut and paste and/or adjust formulas for the &lt;em&gt;Major&lt;/em&gt; column cells following this pattern. &lt;a id=&quot;find-and-replace&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, still on the &lt;em&gt;Minor Expectations&lt;/em&gt; sheet, the &lt;em&gt;Link Value&lt;/em&gt; column must be updated to refer to the current spreadsheet (rather than the originating spreadsheet from the template).&lt;/p&gt;
&lt;p&gt;In the raw web site address from &lt;em&gt;any&lt;/em&gt; cell in the &lt;em&gt;Link Value&lt;/em&gt; column, identify the section noted here in red:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: monospace;&quot;&gt;&lt;code&gt;https://docs.google.com/spreadsheets/d/&lt;/code&gt;&lt;span style=&quot;color: red;&quot;&gt;1byTg8V0vC1wvwpdw5x1-IWji8b3ku9fC3j7KwYkHgrc&lt;/span&gt;&lt;code&gt;/edit#gid=663101658&amp;amp;range=C2&lt;/code&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The precise letters and numbers of that section of the link will vary. Whatever they are for the spreadsheet &lt;em&gt;you&lt;/em&gt; are working in, highlight them, and press Command-C to copy to your clipboard.&lt;/p&gt;
&lt;p&gt;Perform a find and replace for that text (Command-Shift-H).&lt;/p&gt;
&lt;p&gt;Replace that existing text with the characters in the same section of the address for your own copy of the spreadsheet:&lt;/p&gt;
&lt;figure style=&quot;width: 708px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/link-updating.png&quot; loading=&quot;lazy&quot; alt=&quot;Links in the Link Value column must point to the current spreadsheet.&quot; width=&quot;708&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Be sure to configure the find and replace operation as shown:&lt;/p&gt;
&lt;figure style=&quot;width: 500px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/find-and-replace.png&quot; loading=&quot;lazy&quot; alt=&quot;Using the Find and Replace dialog to update the Link Value column.&quot; width=&quot;500&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-three-revise-the-heat-map&quot; tabindex=&quot;-1&quot;&gt;Step Three: Revise the Heat Map&lt;/h3&gt;
&lt;p&gt;Now it is time to modify the heat map to reflect the major and minor expectations of the course you are building the spreadsheet for.&lt;/p&gt;
&lt;p&gt;Here is what the heat map looks like for MCR3U (the course this planning spreadsheet was originally built for in 2017-18):&lt;/p&gt;
&lt;figure style=&quot;width: 780px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/heat-map-logic.png&quot; loading=&quot;lazy&quot; alt=&quot;Heat map for MCR3U showing hidden cells that drive the colour coding logic.&quot; width=&quot;780&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Note that the non-coloured columns (C, E, G, I, et cetera) have been unhidden so that the underlying logic of this sheet can be explained.&lt;/p&gt;
&lt;p&gt;There are several sub-steps involved to update this sheet, but they do not take too long to complete.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, update the text for the strands (bold, larger text in the screenshot above) by copying and pasting from the &lt;em&gt;Overall Expectations&lt;/em&gt; sheet that you have already modified.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, update the text for the major expectations that are part of each strand.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now to adjust the core of the heat map – the colour coded cells.&lt;/p&gt;
&lt;p&gt;Each colour coded cell is shaded based on the cell to its immediate right.&lt;/p&gt;
&lt;p&gt;For example, consider expectation A1.1 in the MCR3U spreadsheet:&lt;/p&gt;
&lt;figure style=&quot;width: 474px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/color-coding.png&quot; loading=&quot;lazy&quot; alt=&quot;Expectation A1.1 has been tagged twice, so it appears in blue.&quot; width=&quot;474&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;It is blue, because the cell to its right contains a 2.&lt;/p&gt;
&lt;p&gt;The cell to the right contains a 2 because expectation A1.1 was tagged twice on the &lt;em&gt;Outline&lt;/em&gt; sheet, meaning the expectation was addressed on two separate occasions throughout the year.&lt;/p&gt;
&lt;p&gt;So how to update this part of the spreadsheet?&lt;/p&gt;
&lt;p&gt;For each minor expectation, we need to update the link (on the colour-coded cell itself, B4 in the image above). We also need to update the formula that counts how many times that expectation was tagged (C4 in the image above).&lt;/p&gt;
&lt;p&gt;For reference, open the &lt;em&gt;Minor Expectations&lt;/em&gt; sheet in one browser window on your computer (if possible, it helps to work on a large monitor while doing this).&lt;/p&gt;
&lt;p&gt;Keep a second browser window open on the &lt;em&gt;Coverage Heat Map&lt;/em&gt; sheet.&lt;/p&gt;
&lt;p&gt;Remember, there is one color coded cell for each minor expectation.&lt;/p&gt;
&lt;p&gt;(If you need to add more cells for additional minor expectations, copy and paste from existing cells so that existing formulas and conditional formatting rules come along for the ride.)&lt;/p&gt;
&lt;p&gt;First adjust hyperlinks for each color coded cell – in this example, we are linking to the minor expectation listed at cell C2 on the &lt;em&gt;Minor Expectations&lt;/em&gt; sheet:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;=HYPERLINK(&amp;quot;#gid=663101658&amp;amp;range=&lt;span style=&quot;color: red&quot;&gt;C2&lt;/span&gt;&amp;quot;,&amp;quot;1&amp;quot;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Next, update the formula in the cell to the right, so that it counts occurrences of the correct curriculum expectation on the &lt;em&gt;Outline&lt;/em&gt; sheet:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: monospace&quot;&gt;=COUNTIF(Outline!$H$2:$Q$100,&amp;quot;&lt;span style=&quot;color: red&quot;&gt;A1.1&lt;/span&gt;&amp;quot;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this example, the formula looks for how many times expectation &lt;em&gt;A1.1&lt;/em&gt; was used as a tag for lessons.&lt;/p&gt;
&lt;p&gt;So, after updating links and the formulas to count expectation tags – that should do it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Of course, a bit of testing of your updated curriculum heat map is advisable.&lt;/p&gt;
&lt;p&gt;As well, columns containing the white cells on the &lt;em&gt;Coverage Heat Map&lt;/em&gt; sheet can be hidden, if desired.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;My hope is that this article is helpful to other teachers.&lt;/p&gt;
&lt;p&gt;If you do adapt this planning spreadsheet to another Ontario course, please &lt;a href=&quot;https://twitter.com/rgordon&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;let me know&lt;/a&gt;. I can add the course you&#39;ve made a template for to the &lt;a href=&quot;https://russellgordon.dev/#existing-courses&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;list provided above&lt;/a&gt;, allowing more teachers to benefit.&lt;/p&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//teaching/a-planning-spreadsheet-with-a-curriculum-coverage-heat-map/" />
        </entry>
    
    
        <entry>
            <title>
                A Peculiar Form of Torment
                
            </title>
            <updated>2019-08-23T19:20:00.000Z</updated>
            <id>https://russellgordon.dev//teaching/a-peculiar-form-of-torment/</id>
            <content type="html">
                &lt;p&gt;A possible future exchange on a popular TV game show:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I&#39;ll take Tedious Math Curricula for $200, Alex.&lt;/em&gt;&lt;br /&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; It&#39;s the Ontario mathematics course where half the expectations involve quadratic relations.&lt;br /&gt;
&lt;strong&gt;Question:&lt;/strong&gt; What is Principles of Mathematics, Grade 10?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you&#39;re a math teacher in Ontario, it&#39;s likely that at some point in your career, you&#39;ve wondered whether your students – or you – could possibly make it through another day studying quadratics.&lt;/p&gt;
&lt;p&gt;Another day of fitting curves to photos of a bridge:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/sipapu.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Sipapu Natural Bridge in the Natural Bridges National Monument in central San Juan County, Utah, United States. A natural stone bridge that spans the White Canyon.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Sipapu Natural Bridge&lt;/h4&gt;
	&lt;p&gt;A stone bridge in central San Juan County, Utah, United States. Photo by Daniel Schwen, Wikimedia, with Desmos overlay by the author.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Or learning &lt;a href=&quot;https://russellgordon.dev/linked-media/Files/standard-form-to-vertex-form.pdf&quot;&gt;one more algebraic procedure&lt;/a&gt; to convert a relation in standard form:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;SVG&quot; display=&quot;true&quot; style=&quot;direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;&quot;&gt;&lt;svg style=&quot;overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.464ex;&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;16.38ex&quot; height=&quot;2.464ex&quot; role=&quot;img&quot; focusable=&quot;false&quot; viewBox=&quot;0 -883.9 7240 1088.9&quot; aria-hidden=&quot;true&quot;&gt;&lt;g stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; transform=&quot;scale(1,-1)&quot;&gt;&lt;g data-mml-node=&quot;math&quot;&gt;&lt;g data-mml-node=&quot;mi&quot;&gt;&lt;path data-c=&quot;1D466&quot; d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(767.8,0)&quot;&gt;&lt;path data-c=&quot;3D&quot; d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(1823.6,0)&quot;&gt;&lt;path data-c=&quot;1D44E&quot; d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;msup&quot; transform=&quot;translate(2352.6,0)&quot;&gt;&lt;g data-mml-node=&quot;mi&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mn&quot; transform=&quot;translate(605,413) scale(0.707)&quot;&gt;&lt;path data-c=&quot;32&quot; d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(3583.3,0)&quot;&gt;&lt;path data-c=&quot;2B&quot; d=&quot;M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(4583.6,0)&quot;&gt;&lt;path data-c=&quot;1D44F&quot; d=&quot;M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(5012.6,0)&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(5806.8,0)&quot;&gt;&lt;path data-c=&quot;2B&quot; d=&quot;M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(6807,0)&quot;&gt;&lt;path data-c=&quot;1D450&quot; d=&quot;M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;mjx-assistive-mml unselectable=&quot;on&quot; display=&quot;block&quot; style=&quot;top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/math&gt;&lt;/mjx-assistive-mml&gt;&lt;/mjx-container&gt;&lt;p&gt;...to its equivalent in vertex form:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;SVG&quot; display=&quot;true&quot; style=&quot;direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;&quot;&gt;&lt;svg style=&quot;overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;17.378ex&quot; height=&quot;2.71ex&quot; role=&quot;img&quot; focusable=&quot;false&quot; viewBox=&quot;0 -948 7681 1198&quot; aria-hidden=&quot;true&quot;&gt;&lt;g stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; transform=&quot;scale(1,-1)&quot;&gt;&lt;g data-mml-node=&quot;math&quot;&gt;&lt;g data-mml-node=&quot;mi&quot;&gt;&lt;path data-c=&quot;1D466&quot; d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(767.8,0)&quot;&gt;&lt;path data-c=&quot;3D&quot; d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(1823.6,0)&quot;&gt;&lt;path data-c=&quot;1D44E&quot; d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;msup&quot; transform=&quot;translate(2352.6,0)&quot;&gt;&lt;g data-mml-node=&quot;mrow&quot;&gt;&lt;g data-mml-node=&quot;mo&quot;&gt;&lt;path data-c=&quot;28&quot; d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(389,0)&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(1183.2,0)&quot;&gt;&lt;path data-c=&quot;2212&quot; d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(2183.4,0)&quot;&gt;&lt;path data-c=&quot;210E&quot; d=&quot;M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(2759.4,0)&quot;&gt;&lt;path data-c=&quot;29&quot; d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mn&quot; transform=&quot;translate(3181.4,477.1) scale(0.707)&quot;&gt;&lt;path data-c=&quot;32&quot; d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(6159.8,0)&quot;&gt;&lt;path data-c=&quot;2B&quot; d=&quot;M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(7160,0)&quot;&gt;&lt;path data-c=&quot;1D458&quot; d=&quot;M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;mjx-assistive-mml unselectable=&quot;on&quot; display=&quot;block&quot; style=&quot;top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;msup&gt;&lt;mrow data-mjx-texclass=&quot;INNER&quot;&gt;&lt;mo data-mjx-texclass=&quot;OPEN&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo data-mjx-texclass=&quot;CLOSE&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/math&gt;&lt;/mjx-assistive-mml&gt;&lt;/mjx-container&gt;&lt;p&gt;You might even struggle to make it through, who knows, dressing up some drab review of quadratic relations by &lt;a href=&quot;https://duckduckgo.com/?q=jeopardy+templates&amp;amp;t=osx&amp;amp;ia=web&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;using a &lt;em&gt;Jeopardy!&lt;/em&gt; template&lt;/a&gt; at the end of a unit of study.&lt;/p&gt;
&lt;p&gt;We are, of course, beholden to the curriculum, old and flawed though it may be.&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;At issue is that each of the tasks described above involve seat work where students primarily manipulate symbols on paper or on a computer. They are not particularly engaging or challenging. To boot, the &lt;em&gt;Jeopardy!&lt;/em&gt; review activity introduces time pressure.&lt;/p&gt;
&lt;p&gt;Given that we must work within a curriculum where the overemphasis on quadratics is a special form of torment for many students, what kind of tasks could we do instead?&lt;/p&gt;
&lt;p&gt;What tasks might better activate the &lt;a href=&quot;http://www.edu.gov.on.ca/eng/studentsuccess/lms/files/tips4rm/TIPS4RMProcesses.pdf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;seven processes at the core of Ontario&#39;s math curriculum&lt;/a&gt;?&lt;/p&gt;
&lt;h2 id=&quot;the-ball-in-a-can-challenge&quot; tabindex=&quot;-1&quot;&gt;The Ball in a Can Challenge&lt;/h2&gt;
&lt;p&gt;In 2006 I had the opportunity to attend the &lt;a href=&quot;https://www.exeter.edu/programs-educators/summer-conference-general-information/anja-s-greer-conference-mathematics-and&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Anja S. Greer Conference on Mathematics and Technology&lt;/a&gt;&lt;sup class=&quot;footnote-ref&quot; id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote&quot; href=&quot;https://russellgordon.dev/#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; at &lt;a href=&quot;https://www.exeter.edu/&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;Phillips Exeter Academy&lt;/a&gt; for the first time.&lt;/p&gt;
&lt;p&gt;Larry Ottman led a weeklong session focused on getting students up, moving, taking measurements, and testing hypotheses in math class.&lt;/p&gt;
&lt;p&gt;With his permission (and his reminder that the task did not originate with him) I will describe the &lt;em&gt;Ball in a Can Challenge&lt;/em&gt; here.&lt;/p&gt;
&lt;p&gt;It says something about me, perhaps, that from Larry&#39;s weeklong session, I&#39;ve only retained this one activity. It&#39;s a pretty good one, though, and just about the only task I can think of where the class often ends with a scene like this:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;video width=&quot;568&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/ball-in-a-can-victory-rsgc.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Victory!&lt;/h4&gt;
		&lt;p&gt;Students at Royal St. George&#39;s College celebrate.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As you see from the video – that&#39;s the task.&lt;/p&gt;
&lt;p&gt;A ball bearing rolls from a ramp.&lt;/p&gt;
&lt;p&gt;If the mathematics are sound, the ball lands in the can.&lt;/p&gt;
&lt;p&gt;Simple, right? It &lt;em&gt;can&lt;/em&gt; be. Let&#39;s dive in!&lt;/p&gt;
&lt;h3 id=&quot;apparatus&quot; tabindex=&quot;-1&quot;&gt;Apparatus&lt;/h3&gt;
&lt;p&gt;Here&#39;s what you need:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/ball-in-a-can-apparatus.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Diagram illustrating the construction of the ramp required for the Ball in a Can Challenge. Two 24-inch lengths of wood are joined with a 2-inch angle iron at a 90-degree angle. An angle iron is attached at the end of each length of wood to allow a 35-inch piece of plastic molding or quarter-round to be inserted inside the bracket. This creates a ramp upon which the ball-bearing will roll from.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Building a Ramp&lt;/h4&gt;
	&lt;p&gt;It takes some time to source materials and build the ramp, but after that initial investment, the activity is straightforward to set up in your classroom year after year. Diagram by Larry Ottman.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;To build the ramp, use a couple of angle irons to join the lengths of 24-inch boards together. The boards are optimally just under an inch high and three inches wide:&lt;/p&gt;
&lt;figure style=&quot;width: 169px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/boards-joined.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Angle irons are used to join the two boards together at a 90-degree angle.&quot; width=&quot;169&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;A strong join between the boards is helpful to be certain they remain perpendicular.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Once that&#39;s done, attach an angle-iron to the end of each board.&lt;/p&gt;
&lt;p&gt;The plastic corner molding, or quarter-round, is placed between the angle irons on the board ends. This creates the curve that the ball bearing will roll down:&lt;/p&gt;
&lt;figure style=&quot;width: 309px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/board-end.jpg&quot; loading=&quot;lazy&quot; alt=&quot;An angle-iron is used to stop each end of the quarter-round.&quot; width=&quot;309&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;The angle-iron should sit just a bit above the board, so that the corner-molding can be squeezed in at each end.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;On the bottom of the ramp (the end the ball will fall from) attach a screw eye.&lt;/p&gt;
&lt;p&gt;Use thread (or lightweight fishing line) and attach it to the screw eye.&lt;/p&gt;
&lt;p&gt;Attach the magnet (or a weight) to the thread. Ensure that the thread is long enough such that the weight hovers just an inch or so above the ground. The thread length will need adjustment based on where you choose to place the ramp in your classroom. A couple of desks, carefully stacked on top of one another, can work, or a ladder. The higher you are able to safely place the ramp, the more fun the activity tends to be. Measure the length of the plumb line accordingly. You&#39;re aiming for something like this:&lt;/p&gt;
&lt;figure style=&quot;width: 453px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/plumb-line.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A weight is suspended from the plumb line that begins where the ball leaves the ramp.&quot; width=&quot;453&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;Here a weight borrowed from the Science department allows the plumb line to hang perpendicular to the floor.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You&#39;ll note that the end of the ramp in this most recent photo is constructed a little differently. The main idea is that, however the ramp is built, you want two boards that remain firmly perpendicular to one another. The ramp must allow for stable placement of the corner molding and for suspension of the plumb line directly under the location where the ball bearing leaves the ramp.&lt;/p&gt;
&lt;p&gt;When you set up the ramp to begin the activity, it&#39;s a good idea to use a C-clamp to secure it to the ladder or desk:&lt;/p&gt;
&lt;figure style=&quot;width: 453px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/c-clamp.jpg&quot; loading=&quot;lazy&quot; alt=&quot;A C-clamp is used to secure the ramp to the desk or ladder on which it is placed.&quot; width=&quot;453&quot; /&gt;
&lt;figcaption&gt;
	&lt;p&gt;It&#39;s no fun at all if students carefully take measurements, perform their calculations, prepare to do the final drop, and then someone accidentally bumps the ramp – requiring the entire process to begin anew.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;setting-the-stage&quot; tabindex=&quot;-1&quot;&gt;Setting the stage&lt;/h3&gt;
&lt;p&gt;How to prepare students?&lt;/p&gt;
&lt;p&gt;I&#39;ve most often run the &lt;em&gt;Ball in a Can Challenge&lt;/em&gt; as a consolidation activity in a unit of study.&lt;/p&gt;
&lt;p&gt;A group of twelve works well, with students mostly partnered and assigned specific roles. This table is adapted from the original by Larry Ottman:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Responsibilities&lt;/th&gt;
&lt;th&gt;Number of students&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Recorder&lt;/td&gt;
&lt;td&gt;Writes down measurements, observes, makes suggestions. A quasi-leadership role.&lt;/td&gt;
&lt;td&gt;One&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dropper&lt;/td&gt;
&lt;td&gt;The person who actually drops the ball. Consistency of drop technique is important! 😅&lt;/td&gt;
&lt;td&gt;One&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Carbon paper&lt;/td&gt;
&lt;td&gt;When the dropper is ready, this team tapes down a sheet of paper on the floor so that the ball is dropping into the middle of the paper. Then they lay the carbon sheet over top of the paper and when the ball is dropped, it leaves a mark on the paper. The dropper continues dropping until they are in enough of a rhythm that they consistently hit the same location on the paper (within a dime&#39;s diameter is sufficient). Once students have the spot, they should mark this on the paper. Another tip – it can be helpful to have the carbon paper team number the drops on the paper (1, 2, 3...) which can help the dropper become consistent more easily.&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Floor measurement&lt;/td&gt;
&lt;td&gt;This team measures the co-ordinates of the point where the ball hits the floor. If you want, you can tell students that the floor represents the horizontal axis, but in my experience, they will arrive at this conclusion themselves after some valuable conversation.&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vertex measurement&lt;/td&gt;
&lt;td&gt;This team measures the co-ordinates of the vertex (where the ball leaves the ramp). You may wish to tell the team they are measuring &amp;quot;where the ball leaves the ramp&amp;quot; and leave it up to them to, again, decide amongst themselves that this represents the vertex, and that it&#39;s on the vertical axis of the mathematical model.&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can height&lt;/td&gt;
&lt;td&gt;This team measures the height of the can above the ground. Some good discussion typically ensues when students debate whether to measure from the top or the bottom of the can.&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can placement&lt;/td&gt;
&lt;td&gt;This team is responsible for placing the can prior to the penultimate drop.&lt;/td&gt;
&lt;td&gt;Two&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;After measurements have been taken for the vertex and where the ball hits the ground, students can algebraically determine the missing value in the quadratic relation. I&#39;ve had groups use both of these forms with success:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;SVG&quot; display=&quot;true&quot; style=&quot;direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;&quot;&gt;&lt;svg style=&quot;overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;17.378ex&quot; height=&quot;2.71ex&quot; role=&quot;img&quot; focusable=&quot;false&quot; viewBox=&quot;0 -948 7681 1198&quot; aria-hidden=&quot;true&quot;&gt;&lt;g stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; transform=&quot;scale(1,-1)&quot;&gt;&lt;g data-mml-node=&quot;math&quot;&gt;&lt;g data-mml-node=&quot;mi&quot;&gt;&lt;path data-c=&quot;1D466&quot; d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(767.8,0)&quot;&gt;&lt;path data-c=&quot;3D&quot; d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(1823.6,0)&quot;&gt;&lt;path data-c=&quot;1D44E&quot; d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;msup&quot; transform=&quot;translate(2352.6,0)&quot;&gt;&lt;g data-mml-node=&quot;mrow&quot;&gt;&lt;g data-mml-node=&quot;mo&quot;&gt;&lt;path data-c=&quot;28&quot; d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(389,0)&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(1183.2,0)&quot;&gt;&lt;path data-c=&quot;2212&quot; d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(2183.4,0)&quot;&gt;&lt;path data-c=&quot;210E&quot; d=&quot;M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(2759.4,0)&quot;&gt;&lt;path data-c=&quot;29&quot; d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mn&quot; transform=&quot;translate(3181.4,477.1) scale(0.707)&quot;&gt;&lt;path data-c=&quot;32&quot; d=&quot;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(6159.8,0)&quot;&gt;&lt;path data-c=&quot;2B&quot; d=&quot;M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(7160,0)&quot;&gt;&lt;path data-c=&quot;1D458&quot; d=&quot;M121 647Q121 657 125 670T137 683Q138 683 209 688T282 694Q294 694 294 686Q294 679 244 477Q194 279 194 272Q213 282 223 291Q247 309 292 354T362 415Q402 442 438 442Q468 442 485 423T503 369Q503 344 496 327T477 302T456 291T438 288Q418 288 406 299T394 328Q394 353 410 369T442 390L458 393Q446 405 434 405H430Q398 402 367 380T294 316T228 255Q230 254 243 252T267 246T293 238T320 224T342 206T359 180T365 147Q365 130 360 106T354 66Q354 26 381 26Q429 26 459 145Q461 153 479 153H483Q499 153 499 144Q499 139 496 130Q455 -11 378 -11Q333 -11 305 15T277 90Q277 108 280 121T283 145Q283 167 269 183T234 206T200 217T182 220H180Q168 178 159 139T145 81T136 44T129 20T122 7T111 -2Q98 -11 83 -11Q66 -11 57 -1T48 16Q48 26 85 176T158 471L195 616Q196 629 188 632T149 637H144Q134 637 131 637T124 640T121 647Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;mjx-assistive-mml unselectable=&quot;on&quot; display=&quot;block&quot; style=&quot;top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;msup&gt;&lt;mrow data-mjx-texclass=&quot;INNER&quot;&gt;&lt;mo data-mjx-texclass=&quot;OPEN&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mo data-mjx-texclass=&quot;CLOSE&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/math&gt;&lt;/mjx-assistive-mml&gt;&lt;/mjx-container&gt;&lt;p&gt;Or:&lt;/p&gt;
&lt;mjx-container class=&quot;MathJax&quot; jax=&quot;SVG&quot; display=&quot;true&quot; style=&quot;direction: ltr; display: block; text-align: center; margin: 1em 0; position: relative;&quot;&gt;&lt;svg style=&quot;overflow: visible; min-height: 1px; min-width: 1px; vertical-align: -0.566ex;&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;19.798ex&quot; height=&quot;2.262ex&quot; role=&quot;img&quot; focusable=&quot;false&quot; viewBox=&quot;0 -750 8750.8 1000&quot; aria-hidden=&quot;true&quot;&gt;&lt;g stroke=&quot;currentColor&quot; fill=&quot;currentColor&quot; stroke-width=&quot;0&quot; transform=&quot;scale(1,-1)&quot;&gt;&lt;g data-mml-node=&quot;math&quot;&gt;&lt;g data-mml-node=&quot;mi&quot;&gt;&lt;path data-c=&quot;1D466&quot; d=&quot;M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(767.8,0)&quot;&gt;&lt;path data-c=&quot;3D&quot; d=&quot;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(1823.6,0)&quot;&gt;&lt;path data-c=&quot;1D44E&quot; d=&quot;M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mrow&quot; transform=&quot;translate(2519.2,0)&quot;&gt;&lt;g data-mml-node=&quot;mo&quot;&gt;&lt;path data-c=&quot;28&quot; d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(389,0)&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(1183.2,0)&quot;&gt;&lt;path data-c=&quot;2212&quot; d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(2183.4,0)&quot;&gt;&lt;path data-c=&quot;1D45F&quot; d=&quot;M21 287Q22 290 23 295T28 317T38 348T53 381T73 411T99 433T132 442Q161 442 183 430T214 408T225 388Q227 382 228 382T236 389Q284 441 347 441H350Q398 441 422 400Q430 381 430 363Q430 333 417 315T391 292T366 288Q346 288 334 299T322 328Q322 376 378 392Q356 405 342 405Q286 405 239 331Q229 315 224 298T190 165Q156 25 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 114 189T154 366Q154 405 128 405Q107 405 92 377T68 316T57 280Q55 278 41 278H27Q21 284 21 287Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(2634.4,0)&quot;&gt;&lt;path data-c=&quot;29&quot; d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mrow&quot; transform=&quot;translate(5709.3,0)&quot;&gt;&lt;g data-mml-node=&quot;mo&quot;&gt;&lt;path data-c=&quot;28&quot; d=&quot;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(389,0)&quot;&gt;&lt;path data-c=&quot;1D465&quot; d=&quot;M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(1183.2,0)&quot;&gt;&lt;path data-c=&quot;2212&quot; d=&quot;M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mi&quot; transform=&quot;translate(2183.4,0)&quot;&gt;&lt;path data-c=&quot;1D460&quot; d=&quot;M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;g data-mml-node=&quot;mo&quot; transform=&quot;translate(2652.4,0)&quot;&gt;&lt;path data-c=&quot;29&quot; d=&quot;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&quot; style=&quot;stroke-width: 3;&quot;&gt;&lt;/path&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;mjx-assistive-mml unselectable=&quot;on&quot; display=&quot;block&quot; style=&quot;top: 0px; left: 0px; clip: rect(1px, 1px, 1px, 1px); -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: absolute; padding: 1px 0px 0px 0px; border: 0px; display: block; overflow: hidden; width: 100%;&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mrow data-mjx-texclass=&quot;INNER&quot;&gt;&lt;mo data-mjx-texclass=&quot;OPEN&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo data-mjx-texclass=&quot;CLOSE&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow data-mjx-texclass=&quot;INNER&quot;&gt;&lt;mo data-mjx-texclass=&quot;OPEN&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mo data-mjx-texclass=&quot;CLOSE&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/math&gt;&lt;/mjx-assistive-mml&gt;&lt;/mjx-container&gt;&lt;p&gt;It&#39;s a good conversation to hear students decide on which equation to work with, and how that connects to the physical apparatus of the task.&lt;/p&gt;
&lt;p&gt;I encourage students to be clear about the meaning of the independent and dependent variables. What does &lt;em&gt;x&lt;/em&gt; represent, and what are its units? And so on. This can be a nudge in the right direction if you&#39;ve noticed the two measurement teams working with different units.&lt;/p&gt;
&lt;p&gt;Finally, once students have the complete equation that describes the path of the ball bearing, it doesn&#39;t take long to decide how they can use the can&#39;s height above the ground, and what this implies for their next steps.&lt;/p&gt;
&lt;p&gt;It&#39;s worth noting that this entire task can run in a far more free-form manner.&lt;/p&gt;
&lt;p&gt;I&#39;ve had students work in groups as small as four, assign roles independently, and meet with success.&lt;/p&gt;
&lt;p&gt;Here&#39;s another photo:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/measuring-ball-drops-rsgc.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Students work together to determine the where the ball bearing hits the ground.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;Where is that ball landing?&lt;/h4&gt;
	&lt;p&gt;After the dropper has become consistent, it&#39;s time to determine exactly where the ball is hitting the ground.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And another step in the process:&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
&lt;img src=&quot;https://russellgordon.dev/img/user/Media/measuring-can-height-rsgc.jpg&quot; loading=&quot;lazy&quot; alt=&quot;Students measure the height of the tomato paste can that is attached to a lab or retort stand.&quot; width=&quot;568&quot; /&gt;
&lt;figcaption&gt;
	&lt;h4&gt;What&#39;s the height of that can?&lt;/h4&gt;
	&lt;p&gt;Once students have a mathematical model to describe the flight of the ball bearing, they must determine the height of the can. What would the next step be?&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Note that should your classroom be carpeted, you&#39;ll need a thin, firm board to place beneath the paper and carbon paper – otherwise the ball bearing will be too cushioned upon impact to allow the carbon paper to make a mark.&lt;/p&gt;
&lt;h3 id=&quot;assessment&quot; tabindex=&quot;-1&quot;&gt;Assessment&lt;/h3&gt;
&lt;p&gt;I have sometimes assessed student work on this task, and sometimes run it simply as a consolidation activity before a major holiday during the school year.&lt;/p&gt;
&lt;p&gt;The task is ripe for recording observations and conversations or assessing learning skills.&lt;/p&gt;
&lt;p&gt;Recall the seven mathematical processes in Ontario mathematics instruction:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Problem Solving&lt;/li&gt;
&lt;li&gt;Reasoning and Proving&lt;/li&gt;
&lt;li&gt;Reflecting&lt;/li&gt;
&lt;li&gt;Selecting Tools and Computational Strategies&lt;/li&gt;
&lt;li&gt;Connecting&lt;/li&gt;
&lt;li&gt;Representing&lt;/li&gt;
&lt;li&gt;Communicating&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.edu.gov.on.ca/eng/studentsuccess/lms/files/tips4rm/TIPS4RMProcesses.pdf&quot; target=&quot;_blank&quot; class=&quot;external-link&quot;&gt;prompts given in this document&lt;/a&gt; can be helpful in guiding your students as they complete the &lt;em&gt;Ball in a Can Challenge&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Before the task begins, I&#39;ve sometimes told the class that later on, they&#39;d each need to author a short reflection, answering these four questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Including a diagram, organize and explain the mathematics used by your group to obtain a successful result.&lt;/li&gt;
&lt;li&gt;What went well in your group&#39;s effort to land the ball in the can?&lt;/li&gt;
&lt;li&gt;What would you have changed about how your group completed the activity?&lt;/li&gt;
&lt;li&gt;Evaluate your own participation in the group. What were your contributions? Were you an effective team member?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In some years, a day or two after the task itself, I&#39;ve given a quiz or test question where a diagram is presented along with key measurements, and then each student must individually solve and explain the problem once more.&lt;/p&gt;
&lt;h3 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;The groups that are most successful are those that can communicate calmly and effectively with one another.&lt;/p&gt;
&lt;p&gt;Don&#39;t permit students to work by trial and error, or &amp;quot;eyeball&amp;quot; measurements. This short-circuits the rich conversations that will ensue when a quantitative approach to problem solving is used.&lt;/p&gt;
&lt;p&gt;It can be a real drag if a group doesn&#39;t land the ball bearing in the can on the first try.&lt;/p&gt;
&lt;p&gt;With a small nudge to reconsider some part of their approach, I&#39;ve never had a group fail to land the ball in the can on their second try.&lt;/p&gt;
&lt;figure style=&quot;width: 568px;&quot;&gt;
	&lt;video width=&quot;568&quot; controls=&quot;&quot; preload=&quot;metadata&quot;&gt;
	  &lt;source src=&quot;https://russellgordon.dev/linked-media/Video/ball-in-a-can-victory-lcs.mp4#t=0.2&quot; type=&quot;video/mp4&quot; /&gt;
	Your browser does not support the video tag.
	&lt;/video&gt;
	&lt;figcaption&gt;
		&lt;h4&gt;Success!&lt;/h4&gt;
		&lt;p&gt;A small group of four students at Lakefield College School ace the challenge.&lt;/p&gt;
	&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;em&gt;Ball in a Can Challenge&lt;/em&gt; takes time to set up, but the payoff for your students will be worth it.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;&lt;a href=&quot;http://www.ahbel.com/&quot;&gt;Nils Ahbel&lt;/a&gt; outlines this very well in &lt;a href=&quot;https://www.youtube.com/watch?v=rOhhAFSsu_g&quot;&gt;Reflections on a 119-Year Old Curriculum&lt;/a&gt;. The content of his talk is well worth looking past the less than ideal audio quality of the recording.
 &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:1&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;The Greer conference at PEA deserves to be explicated in its own article. Here&#39;s the short version: if you&#39;re a math teacher, go. Find a way. You won&#39;t regret it.
 &lt;a class=&quot;footnote-return&quot; href=&quot;https://russellgordon.dev/#fnref:2&quot;&gt;^&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;transclusion internal-embed is-loaded&quot;&gt;&lt;div class=&quot;markdown-embed&quot;&gt;
&lt;script&gt;
document.addEventListener(&quot;DOMContentLoaded&quot;, function removeOtherNav() {
	const landingPage = document.getElementById(&quot;rwhg-navigation-landing-page&quot;);
	landingPage.remove();
	const tutorials = document.getElementById(&quot;rwhg-navigation-tutorials&quot;);
	tutorials.remove();
	const tips = document.getElementById(&quot;rwhg-navigation-tips&quot;);
	tips.remove();
	const projects = document.getElementById(&quot;rwhg-navigation-projects&quot;);
	projects.remove();
	const about = document.getElementById(&quot;rwhg-navigation-about&quot;);
	about.remove();
	document.body.style.opacity=&#39;1&#39;;
})
&lt;/script&gt;
&lt;/div&gt;&lt;/div&gt;

            </content>
            <link href="https://russellgordon.dev//teaching/a-peculiar-form-of-torment/" />
        </entry>
    
    
    
    
    
    
    
    
    
    
    
</feed>
