You can’t talk about the Tampa Bay startup scene for long before the name “Robert Blacklidge” comes up. You’ll often see him at Tampa Bay tech and entrepreneur events, and when he’s not organizing or facilitating hackathons, he’s winning at them. One of his creations, Course Align, made it all the way to finals at Startup Bus 2017 (be sure to check out Gimlet Media’s Startup podcast episodes where they follow the Bus, including the creation of Course Align).
He’s also been bringing tech events and amenities to his home, Lakeland (about 35 miles east of Tampa). Thanks to his work, Lakeland has its editions of 1 Million Cups,Startup Grind, and Techstars Startup Weekend. He also co-founded CO.STARTERS, a 9-week program that teaches entrepreneurs to achieve their long-term goals.
This weekend, he’ll be a mentor at the Feeding the Future online hackathon.
Feeding the Future: A FoodTech hackathon
The world’s food chain supply chains have been greatly disrupted by COVID-19 and its cascading effects. Most of these disruptions will have unpredictable long-term lasting effects on our food systems. The Feeding the Future hackathon’s challenges are all centered around solutions to address and counter these disruptions.
The challenges are:
Sustainable farm-to-fork solutions. How can we use digital technologies to build a more resilient and agile food supply chain for local producers and farmers after CoVid-19 using sustainable farm2fork solutions and further increase e-commerce and home delivery services? How can we apply dynamic models to support seasonal trade and preparation tools for all parts in the food chain?
Reducing carbon “food”prints. The importance of food within cities and urban design is central from several angles. There is a need to transform our urban food systems with a focus on sustainability and resilience.
Make a new and tasty fish product. Baltic Herring is a tasty, small fish found in abundance in the Baltic Sea. Increasing it’s consumption can help lower our carbon footprint. What kind of food product(s) can we create using the Baltic Herring to increase consumption?
Increase Finnish/African food trade. (The hackathon is being organized from Finland.) Africa is an untapped potential market. Finland is known for its world class research in food engineering. What kind of product or services can be utilized to help increase the quality and quantity of food export between Finland and Africa?
NOTE: You can only compete in the Hackathon as a TEAM of two or more members. If you don’t have yet a team, join the hackathon’s Discord community to find one.
I always keep an old computer or two around “just in case,” and it often turns out that they’re useful for all sorts of things. In an age when online access is a necessity and in a line of work where being able to put together a quick web page, application, or server is important, a spare computer — even one that’s a little bit backward by today’s standard — can be a handy resource.
Enter “tinymint,” a Compaq 610 laptop that Anitra got from her old workplace a couple of years back for $50. (You should be able to find a used one, or one with similar specs, for about $100.) We originally got it to give to her parents so that they’d have a half-decent machine on which to surf the web, but we’ve since replaced it with a Chromebook, which requires less maintenance. They gave the Compaq back to us, and I’ve since boosted its RAM to the maximum: A whopping 4 GB, which was pretty respectable in the Windows Vista era when it was manufactured.
An excerpt from the QuickSpecs manual for the Compaq 610.
In case you’re curious, here’s a quick rundown of the specs of my particular Compaq 610. Remember, this laptop is almost old enough to get its own YouTube account or Bat/Bar Mitzvah:
Chipset: Mobile Intel GME965 Express chipset with ICH8M, 800 MHz front side bus. This chipset is from around 2007.
Processor: Core 2 Duo T5870 (2.0 GHz, 2 MB L2 cache, 800 MHz FSB). This is better than the other options: The dual-core Celeron T1500 and the Celeron 560, both of which had the slower 533 MHz bus.
RAM: 4 GB. This is the maximum, which isn’t surprising for a 2009-era computer. 32-bit operating systems were the standard then (64-bit OSs were available, but at a premium), and they’re limited to accessing about 3 GB of memory. The machine originally had 2 GB, and I got replacement RAM from NewEgg for about $20.
Wired networking: Marvell Yukon 88E8042 PCI-E Fast Ethernet Controller
Webcam: 2 megapixels, so it’s 1080p.
Other goodies marking it as a 2009-era computer:
A 56K modem! I don’t think I’ve had dial-up service since 2000. Even during those rare occasions when I need to send a fax, I do it through online fax services.
Separate 1/8″ mic and headphone jacks.
VGA output. Good thing I hung onto that Acer VGA monitor.
There were a few variants of this machine, and I’m a little surprised that this turned out to be one of the better ones — normally companies go with the bottom-of-the-line configurations, especially for computers whose primary purpose was probably producing cover sheets for TPS reports.
Installing Peppermint Linux on the Compaq 610.
I like to think of “tinymint” as a Raspberry Pi with a built-in monitor, keyboard, and battery (although I need to pick up a replacement battery; this one no longer holds any charge). This means that it’s still got some years left in it, where it could function as a server, a runner of automated tasks, or as a budget Python programming machine.
I’m scheduled to teach an “Intro to programming with Python” course in July, and I may actually use this as my demo machine, just to show what’s possible even on a limited budget.
In order to get the most out of this machine, I replaced the Windows with something considerably more lightweight: Peppermint.
Peppermint is a Linux distribution based on Ubuntu, and it’s designed to run on systems with limited resources. To this end, it uses a desktop environment that’s a mix of LXDE’s lxsession session manager and Xfce’s panel and applications menu. Simply put, it’s not going to look as slick as commercial OSs or even other Linux distros, but it’ll be reasonably good-looking and run quite well.
Since Peppermint is a Linux distro, it has all the command-line goodness that a developer needs. I wanted to make “tinymint” a lean mean Python machine, so immediately after Peppermint finished installing, I installed Anaconda Individual Edition and Visual Studio Code, both of which installed and run without any issues.
I’m going to make regular use of “tinymint” and post the occasional report about my experiences with it. If you’re a developer with an older computer and a limited budget, you should look into Peppermint — you might find that it’s exactly what you need.
The current version is “Peppermint 10 Respin,” which came out in December. It’s based on Ubuntu 18.04 LTS, and if you want to know more about this release, check out their announcement.
Want to know more? Here are a couple of recent video reviews of Peppermint:
Greetings, Tampa Bay techies, entrepreneurs, and nerds! Welcome to the June 22, 2020 edition of the list! Here’s this week’s list of online-only events for techies, entrepreneurs, and nerds based in an around the Tampa Bay area. Keep an eye on this post; I update it when I hear about new events, it’s always changing. Stay safe, stay connected, and #MakeItTampaBay!
When will this list include in-person events?
The answer remains, quite emphatically: NOT JUST YET.
Consider the recent spike in cases, as reported in the news:
Do you have an upcoming event that you’d like to see on this list?
If you know of an upcoming event that you think should appear on this list, please let me know!
Join the mailing list!
If you’d like to get this list in your email inbox every week, enter your email address below. You’ll only be emailed once a week, and the email will contain this list, plus links to any interesting news, upcoming events, and tech articles.
Join the Tampa Bay Tech Events list and always be informed of what’s coming up in Tampa Bay!
It uses those parameters to customize the function that it returns: a function that when called, does two things:
It increments its internal counter count, and
returns either word (if it’s time to say the word) or an empty string.
If you find yourself writing a lot of similar code with only minor differences — or worse, cutting and pasting code, followed by typing in those minor differences — you may be looking at an opportunity to use a function like this.
If you prefer to have your functions marked with the keyword function, you can change out the arrow notation and the code will still work:
function wordWatcher(interval, word) {
let count = 0;
return function() {
count++;
if (count === interval) {
count = 0;
return word;
}
return "";
}
}
With wordWatcher defined, creating watchers for Fizz and Buzz is easy:
for (number of Array(100).keys()) {
const potentialFizzBuzz = `${fizzWatcher()}${buzzWatcher()}`;
console.log(potentialFizzBuzz ? potentialFizzBuzz : number + 1);
};
If it’s time to say Fizz, Buzz, or FizzBuzz, potentialFizzBuzz will contain that string. The calls to fizzWatcher() and buzzWatcher() will also increment their internal counters.
If potentialFizzBuzz contains anything, its contents will be printed to the console; otherwise, the current number — which has 1 added to it because array indexes start at 0 and the FizzBuzz game starts at 1 — is printed instead.
You should check out the rest of Frank’s Gist, Fizzbuzzes in many colours, which looks at FizzBuzz solutions written in several languages.
What does it mean for code to be “elegant”, anyway?
In ordinary everyday use, elegant means “pleasingly graceful and stylish in appearance or manner.” The term has been adapted by people in problem-solving fields — science, mathematics, and yes, programming — to mean “pleasingly ingenious and simple”.
And that’s what elegant code is: pleasingly ingenious and simple. This FizzBuzz implementation is elegant because it solves the problem in just over a dozen lines, is simple and concise, and even provides some new insight into programming (the use of custom-generated functions to avoid repetition).
If it fails, it is easy to identify that it is has failed, where it has failed, and why it has failed.
Its behavior (in good and bad conditions) is easy to predict
Check out the following articles — sooner or later, you’ll be interviewed by a programmer who’ll want to know if you’ve given some thought to some of programming’s more philosophical questions, and “What does it mean for code to be elegant?” is one of them:
Yeah, I agree. In fact I like “every Nth” counting problem better than the factorization problem it’s usually treated as. So I was disappointed at all the solutions that didn’t just count, like so
Int n, x
Next(){
If (x == 0) x=n
Return –x
}
— Jenniferplusplus⚧🏳️🌈👩🏻💻 (@jennplusplus) June 17, 2020
They both make a good point. If you’re playing the FizzBuzz game as the original children’s game and not as an exercise to prove that you can actually write a program, you’d do it like this:
The player designated to go first says the number 1, and each player afterwards counts one number in turn. The next player in the circle says 2, and so on.
However, for every third number, instead of calling out the number, the player whose turn it is should say “Fizz”.
…and for every fifth number, instead of calling out the number, the player whose turn it is should say “Buzz”.
The “Fizz” and “Buzz” rules, as the kids would say, stack. In other words, for every number that is both the third and fifth, the player needs to say “Fizz” followed by “Buzz”, or “FizzBuzz”.
So in the spirit of the original game, I’ve put together a FizzBuzz solution that uses “watchers” to keep track of “every xth number”, with one watcher to keep track of when it’s time to say “Fizz”, and another for when it’s time to say “Buzz”. When it’s time to say “FizzBuzz”, they’ll work in tandem.
I created a class called WordWatcher, which can be summarized as shown below:
For those of you who aren’t familiar with Python’s approach to class methods, the first parameter for every method in a class is self. It’s the one parameter you don’t fill when calling a method, because Python calls it implicitly (seemingly in violation of Python’s general guideline that explicit is better than implicit). There’s a reason behind this, and it’s explained in this article: Understanding self in Python.
Also note that instance variables are declared and defined in the initializer method, __init__(), and any reference to them is always preceded by self.
The observe_next_turn() method is meant to be called as the fizzBuzz method proceeds to each new number. It updates the watcher’s internal counter and sets the time_for_word flag accordingly.
The speak() method outputs the watcher’s word if it’s time to say the word, or an empty string otherwise.
For FizzBuzz, we’ll need to create two watchers:
One to keep watch for every third turn, at which point it should say “Fizz”, and
one to keep watch for every third turn, at which point it should say “Buzz”.
With the WordWatcher class defined, we can create these two watchers like so:
It will become handy to have these two watchers in the same place. Since the “ha ha only serious” joke about Python is that everything is a list, let’s put them into a list:
word_watchers = [fizz_watcher, buzz_watcher]
Let’s define a fizzBuzz() function that makes use of this list of word watchers:
def fizzBuzz(word_watchers = [], first = 1, last = 100):
final_result = ""
for number in range(1, 101):
current_result = ""
if len(word_watchers) > 0:
# This part might need some explaining
_ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
if current_result == "":
current_result = str(number)
final_result += current_result
if number < last:
final_result += ", "
else:
final_result += "."
return final_result
If you’ve been following the FizzBuzz series of articles, most of this code will be familiar. The part that might need explaining is the part with the comment “This part might need some explaining”.
Explaining the part that needs explaining
Let’s look at the first of the three lines of code in that part:
_ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
The _ on the left side of the = sign is a throwaway variable. It says “I don’t care about what you do on the other side of the = sign; only that you do something on the other side of the = sign”.
On the right side of the= sign is a list comprehension, which is Python’s “show, don’t tell” way of building lists. This list comprehension simply says “call the observe_next_turn() method of every object in the list”.
Let’s look at the next line:
words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
This line creates a map that converts the watchers in the list into the words they should say for this turn. If the current turn means that it’s time for any one of them to speak, the watcher will be mapped to the word it’s supposed to say. Otherwise, it will be mapped to an empty string.
And now, the final line:
current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
For some reason, map() comes built into Python, but you have to import the functools library in order to use map()’s partner in crime, reduce(). Remember reduce() is a functional programming thingy that takes a collection of items, performs some kind of calculation on that collection, and returns a single value (which you might call a reduction of the collection).
The first argument that I’ve provided to reduce() is a lambda — a small function that isn’t given a name — that simply takes the current item in the list and adds it to the previous collected items. Applied over the entire list, it builds a “total”, which in this case is all the words output by the watchers’ speak() methods concatenated together.
The second argument is the words map converted into a list. This is the list that the reduce() method will operate on.
At the end of those three lines, current_result will contain one of the following:
The empty string
Fizz
Buzz
FizzBuzz
If current_result is still empty at this point, it means that it’s not time for any of the watchers’ words. If this is the case, the string version of the current number is concatenated to current_result:
if current_result == "":
current_result += str(number)
Here’s the code in its entirety:
import functools
class WordWatcher:
def __init__(self, interval, word):
self.counter = 0
self.time_for_word = False
self.interval = interval
self.word = word
def observe_next_turn(self):
self.counter += 1
if self.counter == self.interval:
self.counter = 0
self.time_for_word = True
else:
self.time_for_word = False
def speak(self):
if self.time_for_word:
return self.word
else:
return ""
def fizzBuzz(word_watchers = [], first = 1, last = 100):
final_result = ""
for number in range(1, 101):
current_result = ""
if len(word_watchers) > 0:
_ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
if current_result == "":
current_result += str(number)
final_result += current_result
if number < last:
final_result += ", "
else:
final_result += "."
return final_result
fizz_watcher = WordWatcher(3, "Fizz")
buzz_watcher = WordWatcher(5, "Buzz")
word_watchers = [fizz_watcher, buzz_watcher]
print(fizzBuzz(word_watchers))
You can download fizzbuzz_with_watchers.py and test_fizzbuzz_with_watchers.pyhere (2KB, zipped folder with 2 Python files).
That’s a lot of fuss for Fizzbuzz. Why did you do all that?
Reginald asked me to, and I’ve known and respected him for ages, and JenniferPlusPlus seconded the request.
Wait until you see what customers ask you to do.
Did any of this stuff fly over your head?
Don’t feel bad. I had the same trouble when I first learned functional programming, and that was back in 1991, when the computers that ran functional language interpreters were in labs. I spent a lot of time in Queen’s University’s DEClab, which was full of machines that were cutting edge at the time made by a vendor that no longer exists. Computer time, as well as info on any kind of programming, never mind functional programming, was a lot harder to come by. (In case you were wondering, the language we learned was Miranda.)
If you’ve never worked in Python, some of it can be quite weird. It does eventually make sense.
Let me know, either via email or in the comments, if there’s anything you’d like me to cover in greater detail.
Do you have an alternate solution?
I’ve love to hear about it and present it here! Again, let me know via email or in the comments.
The standard FizzBuzz solution relies on the modulo operator, which it uses to determine if a number is a multiple of 3 or 5.
If you have a math, computer science, or engineering background, the odds are good that you encountered the modulo operator in your studies, as your courses tended to take a mathematical approach to programming. (Remember relational calculus from your intro to databases course?)
If you came into programming from some other field and really got into it because you have a knack for problem-solving, you might not be aware of modulo math. That doesn’t mean that you can’t come up with a FizzBuzz solution.
FizzBuzz minus the modulo operator
When you present the FizzBuzz challenge to a large enough group of programmers — typically a dozen or more — there will be a very determined person who will insist that you provide them with no hints whatsoever. It happens.
When that happens, there’s invariably someone who’s either never heard of the modulo operator (%, which returns the remainder of a division operation) or has forgotten it exists. I’ve also seen a competition comprising quick programming challenges where contestants were told to implement FizzBuzz, but without using modulo.
The more mathematically-inclined will use a method like this:
multiple_of_n() determines if a number n is a multiple of a factor f if the result of n / f is the same as n / f with the fractional part removed.
Occasionally, you’ll run into programmers who are unaware that there are functions to remove the fractional part of a number, either through rounding or truncation. Some of them make up for their lack of math background with a combination of creativity and grit.
I’ve seen one solution that looked something like this:
This function turns the given number into a string, isolates the rightmost character of that string, and then returns True if that character is “0” or “5”, which is true for the string form of numbers that are multiples of 5.
My reaction:
That was nothing compared to one method I saw that someone cobbled together to determine if a number was a multiple of 3. They remembered the old grade-school rule that if you add the digits of a number and the total is a multiple of 3, then the number is a multiple of 3.
Based on that, they wrote something like this:
def multiple_of_3(number):
number_as_string = str(number)
total_of_digits = 0
for digit in number_as_string:
total_of_digits += int(digit)
return total_of_digits in [3, 6, 9, 12, 15, 18]
Again, this function starts by converting the given number into a string. It then iterates through that string character by character, turning each character into a number and adding it to a running total. It then checks to see if that total is in a list of multiples of 3.
Since the standard FizzBuzz challenge is supposed to be performed on the numbers 1 through 100, the largest multiple of 3 will be 99, and the sum of its digits will be 18. Hence the list of multiples of 3 starts with 3 and ending with 18.
My reaction:
But hey, it works!
FizzBuzz plus grit
I’ve seen a handful of people with bachelors’ and even masters’ degrees in computer science face the FizzBuzz test and completely fail to produce working code. I’ve been more impressed by the self-taught coders who, in spite of not knowing about the modulo operator, charge head-first into the problem and solve it. These non-modulo solutions might cause a mathematician to react like this…
…but I think that they’re a sign of grit, which is an important quality for a programmer. These people took what they knew, applied a little creativity, and solved a problem that they shouldn’t have been able to solve. They remind me of a line from aviation pioneer Igor Sikorsky:
According to the laws of aerodynamics, the bumblebee can’t fly, but the bumblebee doesn’t know the laws of aerodynamics, so it goes ahead and flies.
Sooner or later, if you’re working on applications that actually matter, you’re going to run into seemingly insurmountable problems. There will always be the fear that something is just too hard to do. Impostor syndrome may rear its ugly head. Developing grit — and yes, it can be developed — is important, and it’s a quality I look for when forming a team.