Monday, September 16, 2024
Pedal and Paddle in the Edmonton River Valley
Monday, November 27, 2023
Countdown Timer in Google Sheets
If you've ever wanted to have a Google Sheet up the screen together with a countdown timer, for example if you have a pivot table leaderboard for a hackathon, you can use Google Apps Script.
From your Google Sheet, click on the Extensions menu and choose Apps Script to open the script editor.
Paste in the following code into the editor:
function onOpen(e) { var ui = SpreadsheetApp.getUi(); ui.createMenu('Timer') .addItem('Countdown Timer in Sidebar', 'showSidebar') .addToUi(); } function showSidebar() { var html = HtmlService.createHtmlOutputFromFile('countdown'); html.setTitle('Countdown Timer'); SpreadsheetApp.getUi().showSidebar(html); }
Then click the + button near the top left to add a new file, and choose HTML. Type countdown as the file name, then paste the following code into the editor:
<!DOCTYPE html> <html> <head> <base target="_top"> </head> <body> <div id="buttons"> <button id="thirtyMinutes" onclick="thirtyMinutes()">30 minutes</button><br> <button id="fifteenMinutes" onclick="fifteenMinutes()">15 minutes</button><br> <button id="tenMinutes" onclick="tenMinutes()">10 minutes</button><br> <button id="twoMinutes" onclick="twoMinutes()">2 minutes</button><br> <button id="oneMinute" onclick="oneMinute()">1 minute</button><br> </div> <div id="countdown" style="text-align:center;font-size:50px"></div> <script> function thirtyMinutes() {startCountdown(30);} function fifteenMinutes() {startCountdown(15);} function tenMinutes() {startCountdown(10);} function twoMinutes() {startCountdown(2);} function oneMinute() {startCountdown(1);} function startCountdown(minutes) { document.getElementById("buttons").style.display = "none"; // hide the buttons div let count = parseInt(minutes) * 60; if (!count > 0) { count = 60; } let displayTime = "0:00"; const timer = setInterval(function() { count--; displayTime = Math.floor(count / 60) + ":" + ("0" + count % 60).slice(-2); document.getElementById("countdown").innerHTML = displayTime; if (count < 60) { document.getElementById("countdown").style.color = "red"; } if (count === 0) { clearInterval(timer); document.getElementById("countdown").innerHTML = "0"; //alert("Time's up!"); } if (count < 0) { clearInterval(timer); document.getElementById("countdown").innerHTML = "0"; } }, 1000); } </script> </body> </html>
You can also edit the code to add or remove buttons, and change the style of the buttons and text.
Tuesday, October 3, 2023
I've changed my mind about AI governance
Recently, the Canadian government launched a voluntary code of conduct related to generative AI. Many organizations have agreed to this code of conduct, although support has not been universal.
This was the topic of our last biweekly "AI Issues and Ethics" discussion, what role should there be for regulation of artificial intelligence? It was a great conversation with plenty of dissent, as always, and I found my opinion changing as a result of the wisom of the participants.
I used to be skeptical about the idea of government involvement in regulating artificial intelligence, assuming that policymakers lacked the expertise and agility to make informed decisions. This is a rapidly evolving and technically complicated field and, as others have argued, regulation must stifle innovation. I often argued for fewer regulations and restrictions on technologies, or at least suggested that existing rules and laws related to privacy or safety were sufficient to address these new technologies.
However, my views have evolved, and I now firmly believe that some level of governance is essential to ensure the responsible and ethical development and deployment of AI technologies.
Lawmakers don't need to understand the complexities of internal combustion engines, or electric vehicles for that matter, in order to set speed limits on our roads. They rely on experts, data, and an understanding of societal needs to establish safe parameters. Speed limits are not designed to stifle our driving.
And to use a similar analogy, there was a time in Alberta the seatbelt use in cars was not compulsory. I'll admit that I didn't always wear a seatbelt, even though I knew it was safer to do so. States with fewer requirements for motorcycle helmets have increased rates of injuries and deaths. Humans don't always make the best decisions around our own safety.
That's not to say that the government will always make the best decisions either. There will be instances where regulations fall short or overreach, but we shouldn't abandon the idea of AI governance entirely. Through an iterative process that is open to feedback and fosters collaboration among stakeholders, experts, and policymakers, legislation can be amended and refined. Regulations should be adaptive and responsive to evolving needs and norms of society.
I would argue that we don't require an absence of regulations in order to innovate, nor should we rely solely on the judgement of technology organizations to work for the good of humankind. By fostering collaboration, making informed decisions, and committing to ethical principles, A voluntary code of conduct is a good start, and I hope that we can create an and safe suite of artificial intelligence tools for everyone.
And let me know if you'd be interested in participating in some of these "AI Issues and Ethics" discussions.
Tuesday, February 21, 2023
Ethical Questions Related to Discriminative and Generative Artificial Intelligence
It suddenly seems that everyone is talking about artificial intelligence, computers doing things that look like they require intelligence. Tools that generate images or text have gotten fairly good and easy to use.
These generative AI tools are trained to create new content based on their input data sets. Discriminative AI tools, on the other hand, are trained to differentiate among different classes of input and predict which class a new observation should belong to.
My impression is that people are more comfortable with discriminative AI, with applications in autonomous vehicles and facial recognition, than with generative AI that seems to intrude on our uniquely human creativity. Of course there is a spectrum of opinions from excited techno-optimism to worries that this will bring about the end of civilization.
Lately I've been a part of many discussions about ethical questions surrounding artificial intelligence, particularly in education. For many of them there aren't, or aren't yet, good answers, but they certainly make for interesting debate. These are in no particular order, and feel free to use them in your own conversations.
- Is it plagiarism or cheating to use generative AI tools?
- Can we accurately detect if students are using these tools? Is this something we should worry about?
- What are we training students for? Is school about job training?
- Why do we make students write?
- What are uniquely human skills and competencies we need to foster?
- If we block AI tools on our educational networks and devices, does the problem go away?
- Are we comfortable with doctors or drivers using AI?
- Can AI take over some of the mundane parts of our jobs (or lives)?
- How would we feel about a facial recognition attendance system?
- Is it ethical to have AI help us draft emails, or blog posts?
- What does education look like if teachers use AI to help generate questions and students use it to help generate answers?
- Are we okay with corporations using student questions and responses to help train their models?
- Will bias in the training data lead to increased societal polarization?
- Are there analogies to historical inventions that we can learn from?
- Will AI disintermediate students and learning?
- Does over-reliance on AI lead to skill loss?
- Will we lose jobs? Will this change jobs?
- Does AI exacerbate inequality?
- Will AI lead to homogenization of culture?
- Do we like spell check, autocorrect, autofill, predictive text, and autoreplies?
- Will generative AI answers spell the end of internet search?
- If we enjoy doing things, should we use AI or machines to do those things? Should we try to prevent AI or machines from doing those things?
- Is AI worth the environmental impact?
- What might AI tools look like in six months? How about in five years?
Hopefully these questions can help spark some thoughful and spirited discourse.
Saturday, May 7, 2022
Creating, Editing, and Sharing Jupyter Notebooks
Saturday, December 11, 2021
Automatically Changing a YouTube Video's Privacy With Google Apps Script
Recently we had posted a video that needed to be available during a specific time. The starting availability is taken care of by setting it to premiere. However there's no option for having it unavailable at the end of the time period, so we needed to write some code for that.
Google Apps Script is a good choice for this, since it has a YouTube service that you can enable as well as triggers that can run code at a certain time.
Create a new Apps Script project and paste in the following code:
Then enable the YouTube Service and create a new trigger to run the updateVideoPrivacy function at a time-driven specific date and time. The code will then set your most recently uploaded YouTube video to private at the time you specified.
Saturday, October 30, 2021
Coding Challenge 3
The third coding challenge is up at misterhay.github.io/coding-challenges, along with a possible solution to this challenge and last month's challenge.
Thursday, September 30, 2021
Small Coding Challenge 2
The second coding challenge is up at misterhay.github.io/coding-challenges, along with a possible solution to this challenge and last month's challenge.
Saturday, September 11, 2021
Fixing a formula in multiple Google Sheets
Recently we realized that there was a calculation error in a Google Sheet template, and unfortunately we had already made a copy of it for each teacher.
Rather than opening each Sheet and manually making the correction, I wrote a Google Apps Script to automatically make the replacements. Here is the code in case it is helpful for anyone else:
function loopThem() { var folderId = 'aaaaaaaaa'; // the folder containing all of the sheets to be corrected var folder = DriveApp.getFolderById(folderId); var files = folder.getFiles(); while (files.hasNext()) { var file = files.next(); var id = file.getId(); fixIt(id); } } function fixIt(id) { var rangeToFix = 'P1:P50'; // the range in each sheet that contains the error var replaceThis = '$A'; var replaceWithThis = '$C'; var ss = SpreadsheetApp.openById(id); var range = ss.getRange(rangeToFix); var formulas = range.getFormulas(); for (var i=0; i<formulas.length; i++) { var formula = formulas[i][0]; var newFormula = formula.replaceAll(replaceThis, replaceWithThis); formulas[i][0] = newFormula; } range.setFormulas(formulas); }
Sunday, August 29, 2021
Small Coding Challenge 1
This year I'm going to design some coding challenges, and hopefully release them at least once a month.
The first coding challenge is up at misterhay.github.io/coding-challenges.
Saturday, March 13, 2021
Quick Exploratory Data Analysis with SweetViz
I recently came across a Python library that is useful for quick exploration of a dataset (or two) in a Jupyter notebook, SweetViz.
Code:
try: import sweetviz except: !pip install sweetviz --user import sweetviz import pandas as pd df = pd.read_csv('https://raw.githubusercontent.com/callysto/hackathon/f7454f5d9234df2575ceb7b8983340e512fad24d/SustainabilityOnMars/Tutorials/pets_from_bootstrap_world.csv') analysis = sweetviz.analyze(df) analysis.show_notebook() # or export with show_html()
Here is a brief notebook demonstration.
Saturday, January 9, 2021
Getting Student Submission Data from Brightspace with Python and Selenium
As a teacher with students in multiple Brightspace courses, I was looking for a dashboard to show which students have unsubmitted assignments. While Brightspace does have an API available, I decided that it wasn't going to work for a few reasons. There are also commercial (non-free) plugins that can do most of what I was looking for, but this was a good opportunity to explore scraping of content from dynamic web pages with Python.
You may be familiar with the Python Requests and Beautiful Soup libraries, which are great, but since Brightspace is requiring a Microsoft login I needed to go with Selenium. Selenium is designed for automating web browser interactions, which means we can use it to log in to a site and scrape pages.
While Selenium can be installed and run locally, it also works in a Colab notebook:
!apt update !apt install chromium-chromedriver !pip install selenium from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By options = webdriver.ChromeOptions() options.add_argument('--headless') options.add_argument('--no-sandbox') browser = webdriver.Chrome(options=options)
Once that is set up, we need to log in to our Brightspace server:
email = 'teacher@example.com' base_url = 'https://example.brightspace.com' import getpass # so you don't show your password in the sourcecode password = getpass.getpass() email_field = (By.ID, 'i0116') password_field = (By.ID, 'i0118') next_button = (By.ID, 'idSIButton9') browser.get(base_url) WebDriverWait(browser,10).until(EC.element_to_be_clickable(email_field)).send_keys(email) WebDriverWait(browser,10).until(EC.element_to_be_clickable(next_button)).click() WebDriverWait(browser,10).until(EC.element_to_be_clickable(password_field)).send_keys(password) WebDriverWait(browser,10).until(EC.element_to_be_clickable(next_button)).click() WebDriverWait(browser,10).until(EC.element_to_be_clickable(next_button)).click()
From there it's a matter of scraping the course progress pages as we loop through the course IDs and student IDs. I may update this post later with an automated way to scrape these IDs, but for now we need to look them up on Brightspace and code them in:
import pandas as pd df = pd.Series(students).to_frame('ID') for course in courses: course_id = courses[course] submissions = [] for student in students: student_id = students[student] url = base_url+'/d2l/le/classlist/userprogress/'+str(student_id)+'/'+str(course_id)+'/Assignments/Details' browser.get(url) WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "span[class^='d2l-textblock']"))) elements = browser.find_elements_by_css_selector("span[class^='d2l-textblock']") #elements = browser.find_element(by=) # because the other thing is deprecated I guess #submitted = elements[13].text[1:-1] # to get a fraction submitted = elements[13].text[1:-1].split('/')[0] # to get just the numerator submissions.append(submitted) df[course] = submissions df.to_csv('student-submissions.csv') df
This will give us a Pandas DataFrame (and a CSV file) with information about how many assignments each student has submitted in each course. We can manipulate this a bit to create some visualizations, but perhaps that's a post for later. For now, here's part of a chart that we could generate:
Let me know if you try this or if you come across anything that should be corrected.
Saturday, September 19, 2020
Bookmarklet for Generating a Link to Copy a Google Doc, Sheet, Slides, or Drawing
If you want students to create a copy of a Google Doc, Sheet, Slides, or Drawing, you can replace the /edit at the end of the link with /copy.
To make that easier, I've created a bookmarklet. To set it up for yourself, drag the following link to your bookmark bar or menu:
Then when you have a Doc, Sheet, Slides, or Drawing open (and you've set the sharing permissions) you can click the bookmarklet and it will generate a link that you can copy and send to your students. When they click the link it will prompt them to make a copy.Tuesday, June 9, 2020
Streaming OBS Recordings to YouTube
second_stream.py and run from there.xxxx-xxxx-xxxx-xxxx with your stream key from YouTube Studio, and /home/username/Videos with the path to the folder where OBS records your videos. You may also need to include the ffmpeg_path.Saturday, February 29, 2020
Authoring Open Educational Resources using only Open Source Software
Here are some of my suggestions, please comment if anything is missing. And I do understand the hypocrisy of posting this on a Google-hosted blog.
Writing Text
Text is still often the primary medium for OER, and there are a number of great open-source text-authoring tools. LibreOffice is a great office suite, and it is similar to traditional office suites so there shouldn't be much of a learning curve.
If you prefer collaborative writing, perhaps check out Nextcloud. You'll need to host it somewhere, if you are in Alberta consider Cybera's Rapid Access Cloud which uses OpenStack.
Diagrams and Graphics
Inkscape is a great vector editing and layout program. For image editing and creation, check out GIMP, Krita, or MyPaint.
Audio
One of the best simple audio recording and editing programs is also open source, Audacity. There are others, of course, but it should do everything you need.
Video
My favorite open-source video editing program is Open Shot, but you may also want to check out Shotcut.
Hosting video is another issue, though. You can host videos in a learning management system such as Moodle, or check out alternatives such as MediaGoblin, Kaltura, or ClipBucket.
Operating System
Linux has gotten much easier to install and use if you'd like to replace Windows or MacOS. My current favorite distribution is Peppermint.
Hosting
As previously mentioned, Albertans can avoid the big five cloud providers by running servers on RAC, but your institution may have self-hosted instances of Pressbooks or similar open-source hosting platforms.
Hopefully those cover anything you may need to use when creating OER with OSS. In some cases these tools are preferable to commercial products.
Of course if you are philosophically opposed to proprietary software then you are probably already familiar with most of these.
As always, please comment if you have any other suggestions.
Monday, February 3, 2020
Getting new copies of Jupyter notebooks with shutil and nbgitpuller
If you would like to update your copy of notebooks, for example on the Callysto Hub, you can delete the folder and pull the files from GitHub again. This is useful if something no longer works, or if the repository has been updated.
Unfortunately you can’t just select a directory in Jupyter hub and delete it if it contains files. One way to delete a folder, though, is to use the Python command shutil.rmtree() which is a shell utility command that will remove a whole directory tree.
To remove a folder, create a new Python 3 notebook in the same folder as the one you want to delete (but not inside the folder to be deleted).
In a code cell, type (or paste) the following two lines:
import shutil
shutil.rmtree('curriculum-notebooks')
Replace curriculum-notebooks with the name of the folder you would like to delete. Then run the cell, and you should see that the folder no longer exists.
Then you can click on an nbgitpuller link, for example from callysto.ca, that pulls down a new copy of the repository or notebook files that you are interested in.
You can also see the process in this video.
Wednesday, January 29, 2020
Using the Bitly API with Google Apps Script (JavaScript)
Assuming that you are developing applications or scripts that will be used for a single account you don't need to worry about OAuth authentication, you can get a generic access token from this link.
If you haven't already, create a Google Apps Script. Here are some functions you can use:
Hopefully that's enough to get you started. You can browse the rest of the Bitly API documentation for other functions.
Thursday, January 2, 2020
Looking forward to technologies of the 2020s
Better digital assistants and smart devices
Smart speakers and phone-based digital assistants are useful for some things, but we still find ourselves repeating or rewording commands. There are also quite a few instances of "I can't help with that yet". I'm optimistic that we will get to the point of our digital assistants learning how to work for us, and our smart homes adjusting to our lifestyles and patterns without us having to continually yell at them and reconnect devices to the WiFi. These devices and services should make it less work for us to accomplish tasks.
More automation of uninteresting tasks (including driving)
I'm a big fan of freeing up humans to accomplish uniquely human achievements, or watch more streaming video if they prefer. To help achieve that, I'm looking forward to more automation of tedious or dangerous tasks. While this may lead to more unemployment, or less depending on who you listen to, maybe we can get to the point as a society of eliminating jobs that people dislike. And perhaps decrease our workload without decreasing our standard of living, so that we have more time for volunteering and leisure activities.
Better virtual reality and augmented reality
VR seems to be used primarily for leisure activities such as video games, and perhaps some basic virtual field trips, but there are many other interesting applications. It still feels like early days, especially with AR, but the technological capabilities and developer proficiencies are improving. I'm particularly excited about the potential for psychological treatments using VR and AR.
Advances in psychology and neuroscience
Technologies such as functional magnetic resonance imaging are giving us better insights into how brains work, and it feels like we are just at the beginning of our understanding. We may start to see useful mind-computer interfaces, and at some point even the ability to create backups...
Improved information literacy
As we understand more about how our minds work, perhaps we can devote more resources to helping people distinguish reality from fiction. There seems to be a growing recognition that disinformation and "face news" are issues, but no consensus about what is fake and how to deal with this issue. I'm optimistic, however, that it is a solvable problem. It may require a re-think of how we remunerate individuals and organizations, and our advertising-based economy.
eSports
We've seen a growing phenomenon of watching other people play video games, and "cyberathletes" making the kind of money that professional athletes can make. Not sure if this will supplant traditional sports, or if we would want them to, but the risk of concussions is lower. There is automated comment moderation in some streams, but the communities tend to be somewhat toxic, especially for female gamers. Although I don't usually recommend technological solutions to behavioral problems, internet filtering for example, maybe technology can help teach us to be better people.
Ubiquitous data access
I am in favor of better data access, and improved information for education and decision making (I believe Wikipedia is one of humanity's greatest achievements). We are seeing intriguing ideas about ways to provide internet access in remote areas, such as drones, balloons, or low Earth orbit satellites (which hopefully won't interfere with astronomy). This is particularly useful for underprivileged areas and people groups.
Blockchain
Beyond cryptocurrencies, which may help when government-backed currencies are subject to catastrophic inflation, there are other applications of blockchain ledgers for identity management and verification, supply chain tracking, contracts and asset transfer, and other financial services such as payments and escrow. We may even see blockchain-based voting.
These are some of the technologies and trends that I'm thinking about these days. Of course we will likely see some unexpected dark horse technologies have significant impacts on our lives and society. But as they say, predictions are difficult. What are your thoughts?
Monday, November 18, 2019
Automated Scheduling of Facebook Live Video via Google Apps Script
This will require a Facebook account (with admin rights to a page if you broadcast through that page) as well as a Google account. We are going to create a Google Spreadsheet with an associated Google Apps Script that will run every week to schedule your live video.
- Create a Google Spreadsheet
- Under the Tools menu, click Script editor
- Into that new script paste the contents of this file
- Create a new Facebook App under the My Apps menu on developers.facebook.com
- Under Settings click on Basic and copy your App ID and App Secret (click Show) into the appropriate places back in your Google Script editor
- Setup gsuitedevs' OAuth2 library for Google Apps Script by following the four steps there
- Run the logRedirectUri function in your Google Script, then under the View menu click Logs, copy the Redirect URL (starting with http)
- On the Facebook developer page, set up Facebook Login for your app
- Under the Facebook Login Settings, paste in the OAuth Redirect URI that you copied earlier
- In your Google Script, run the scheduleLivestream function, this won't actually schedule anything yet but instead will log a URL for you to paste into your browser to authorize the script (under the View menu click Logs, or look at the original spreadsheet)
- Using the Facebook Graph API Explorer, add the following permissions to your app: pages_show_list, manage_pages, publish_pages, publish_video
- Run the Google Script function scheduleLivestream again and watch for any errors, if it successfully schedules a broadcast then you'll see a new line in your spreadsheet
- Add triggers to your Google Script: under the Edit menu click Current project's triggers
- Click Add Trigger and set the options:
- scheduleLivestream
- Head
- Time-driven
- Week timer
- Every Wednesday (or whatever you prefer)
- 1pm to 2pm (or whatever)
- then click Save
- Click Add Trigger and set the options:
- onOpen
- Head
- From spreadsheet
- On open
- then click Save
- In your Google Script, change the following lines:
- var status = 'SCHEDULED_UNPUBLISHED'; to var status = 'SCHEDULED_LIVE';
- var day = dateNow.getDate() + ((7 - dateNow.getDay()) % 7); to var day = dateNow.getDate() + ((9 - dateNow.getDay()) % 7); // for Tuesday
- var newDate = new Date(year, month, day, 10, 25); to the time you'd like to start the broadcast
- you can also change the var title line to whatever you'd like
- Run the scheduleLivestream function again to test, and to make sure everything has been authorized
- Check at some point after the Trigger time you set to make sure that the broadcast has been scheduled
Thursday, November 7, 2019
The Benefits of Small Conferences
Events like the annual ISTE Conference with about 20,000 attendees are impressive, and you may meet someone like Mayim Bialik, but it feels like the odds of meeting someone with whom you can have sustained and ongoing discussions are decreased. There is an ocean of information available, but I'd argue that through the internet we already have that available.
So perhaps the ideal conference size is between 150 and 500 participants. Large enough for a diversity of perspectives, but small enough to be able to meaningfully share those perspectives and get to know people. We tend to value growth as a measure of success, but perhaps we need other metrics.
Thoughts?



