Thanks to Chloe Condon for the find, and Sophie Mallinson for the original tweet!
Category: Uncategorized
Every week, I compile a list of events for developers, technologists, tech entrepreneurs, and nerds in and around the Tampa Bay area. We’ve got a lot of events going on this week, and here they are!
Monday, May 21
- Tampa Bay DevOps Monthly Meetup – Distributed Tracings @ Salesforce Tampa, 6:00 PM to 9:00 PM
- Code for Tampa Bay Brigade — St. Petersburg May Meetup – Taking Civic Tech Across the Bay! @ TEC Garage, 6:00 PM to 8:00 PM
- Kids Academy with Suncoast Developers Guild Jr. @ Agile Thought, 6:30 PM to 8:30 PM
- Largo Board Games Meetup — Dice Throne Demo Night! @ Game On, Movies and Games, 7:00 PM to 9:00 PM
- Fusion 360 Deep Dive (8 Weeks) @ Tampa Hackerspace, 7:00 PM to 10:00 PM
- South Tampa Toastmasters @ Unity of Tampa, 7:00 PM to 8:15 PM
- Digital Photo Artists — Presets, Textures, Layers, Masks, and Blending Modes By Linda Romero @ 7:00 PM to 9:00 PM
- Nerdbrew Trivia — Pints & Pixels + Mario Kart 64 Tournament! @ Brew Bus, 7:00 PM to 11:00 PM
Tuesday, May 22
- Business Development and Sales — Leads and Coffee @ Belleair Coffee Company, 7:45 AM to 9:00 AM
- Westshore Toastmasters @ FIVE Labs, 12:00 PM to 1:00 PM
- Tampa Bay Writing, Publishing & Marketing Meetup — Week 4 – How Not to Get Sued for Your Book @ The Kaizen Collaborative, 5:30 PM to 8:30 PM
- Entrepreneurs & Startups – Bradenton Networking & Education — Use-Cases for Blockchain: Will Blockchain Disrupt Your Industry? @ Station 2 Innovation Center, 5:30 PM to 7:30 PM
- Tampa Bay AWS User Group — AWS Elasticity and Auto-Scaling @ Keiser University Tampa, 6:00 PM to 8:00 PM
- Weekly Open Make Night @ Tampa Hackerspace, 6:00 PM to 10:00 PM
- Star Wars X-Wing Open Play @ Critical Hit Games, 6:00 PM to 9:00 PM
- Tampa iOS Meetup — Saving data in iOS apps / How to take what you know and write an app, part 2 @ Sourcetoad, 6:30 PM to 8:30 PM
- Game Club Tampa Meetup — Tuesday Nite Roleplayers (RPGs) (LFP) @ Grand Arena of Mind Expansion, 6:30 PM to 9:30 PM
- Brandon eMarketing Groups — Internet Marketing for Business Owners @ 7:00 PM to 9:00 PM
- St. Pete Beers ‘n Board Games Meetup for Young Adults @ Flying Boat Brewing Company, 7:00 PM to 10:00 PM
Wednesday, May 23
- OPEN/Women’s Networking Event – 1 Million Cups — Entrepreneur Collaborative Center (ECC), 8:00 AM to 9:00 AM
- 1 Million Cups St. Pete @ St. Petersburg Greenhouse, 9:00 AM
- 1 Million Cups Tampa — Geo Leads Pro / A Gift To Africa @ Mark Sharpe Entrepreneur Collaborative Center, 9:00 AM
- Speakers Circle Toastmasters @ Fort Brooke Parking Garage 3rd Floor Conference Room, 12:00 PM to 1:00 PM
- PoweredUP Technology Festival @ Mahaffey Theater, 1:00 PM to 6:30 PM
- Tech On Tap Tampa — Come join us for this month’s TECH ON TAP networking happy hour! @ World of Beer, 5:00 PM to 8:00 PM
- Grand Gamers of St. Petersburg Board Game Night @ Critical Hit Games, 6:00 PM to 11:30 PM
- Tampa Bay UX Group — Get Out of the Building! How to Build a UX Research Practice @ Kforce, 6:30 PM to 8:00 PM
- 3D Printer Orientation @ Tampa Hackerspace, 7:00 PM to 9:00 PM
- Blockchain Enthusiasts — Blockchain/Cryptocurrency Meetup: News, Q&A, Networking, Social @ BlockSpaces, 7:00 PM to 10:00 PM
- Learn to Pick Locks @ Tampa Hackerspace, 7:00 PM to 9:00 PM
- Champions of Azeroth — “Insert Coins To Care” For Alzheimer’s Association @ The Lowry Parcade and Tavern, 7:00 PM to 10:00 PM
- Women in Linux — Understanding Linux @ 7:00 PM
- Nerdbrew Trivia — Games & Grog @ Peabody’s! @ Peabody’s Billiards and Games, 7:00 PM to 11:00 PM
Thursday, May 24
- Tampa Bay Tech Events — Geek Breakfast @ Jimbo’s Pit Bar-B-Q, 7:30 AM to 9:30 AM
- Tampa Bay Professionals (IT, Sales, HR & more) — Building YOUR Career Skills Using Tuition Assistance @ WebEx Live-Online Session, 8:00 AM to 8:30 AM
- ENGAGE – A Network for Evolving Entrepreneurs — Mastering you inner game for entrepreneurs with Dr. Linda @ 9:00 AM
- Tampa Cybersecurity Meetup — Expert Series: Pablo Breuer @ SecureSet Tampa Campus, 5:00 PM to 7:00 PM
- Brandon Boardgamers — Let’s Game on Thursdays @ Panera, 3490 Lithia Pinecrest Road, Valrico, 5:30 PM to 9:30 PM
- Code Lakeland — Serverless React Web Applications Using AWS by Gerardo Renovales @ Catapult, 6:00 PM to 8:00 PM
- Power BI User Group Meeting @ CoonnectWise, 6:00 PM to 8:00 PM
- Tampa Bay Salesforce Developer Group — Never Stop Deploying with SalesforceDX @ Bisk Education, 6:30 PM to 8:30 PM
- 3D Printing Guild @ Tampa Hackerspace, 7:00 PM to 10:00 PM
- Tampa Bay Social Media Meetup — WordPress @ Tampa Bay Technology Center, Thursday, May 24, 2018, 7:00 PM to Thursday, May 31, 2018, 9:00 PM
- Hyperledger Tampa — Introduction to Hyperledger @ BlockSpaces, 7:00 PM to 9:00 PM
Friday, May 25
- Lean Coffee for All Things Agile (Westshore) @ Panera Bread, 112 S Westshore Blvd, Tampa, 7:30 AM to 8:30 AM
- Café con Tampa @ Oxford Exchange, 8:00 AM to 9:00 AM
- May 2018 Homebrew Hillsborough @ SecureSet Tampa Campus, 8:30 AM to 11:30 AM
- Electronics Bench Orientation (Members Only) @ Tampa Hackerspace, 7:00 PM to 9:00 PM
Saturday, May 26
With data science and machine learning a hot topic these days (and possibly a path to the hottest job at the moment), you may be experimenting with statistics, and in doing so, you may be rolling your own statistics methods. Don’t!
You wouldn’t chop down trees for lumber for a home renovation project; you’d go to Home Depot or a lumber store and get standard cuts of wood. In the same vein, you should make use of ready-made statistics libraries, which are proven, road-tested, and let you focus on what your application actually does.
These are the ones I use:
JavaScript: jStat
If you’re doing stats in JavaScript, you want jStat, which provides not just the basic statistical functions, but all manner of distributions, including Weibull (β), Cauchy, Poisson, hypergeometric, and beta distributions, with probability density functions (pdf), cumulative density functions (cdf), inverse, mean, mode, variance, and a sample function, allowing for more complex calculations.
jStat is contained in a single file: jstat.js; there’s also the minified version, jstat.min.js.
You can also get the most up-to-date version from jsdelivr’s content delivery netowork at http://cdn.jsdelivr.net/npm/jstat@latest/dist/jstat.min.js
To install it via npm, just do this on the command line…
npm install --save jStat
…and if you’re loading it while in Node, reference the child object. Here’s a session in Node:
var jStat = require('jStat').jStat // Now we can use jStat! let data = [20, 30, 30, 40, 40, 40] jStat.mean(data) // 33.333333333333336 jStat.median(data) // 35 jStat.mode(data) // 40 jStat.stdev(data) // 7.453559924999299
Python: Python’s statistics library
For more in-depth statistics functions, you’ll want to go with Scipy, but for the basics — namely averages and measures of central location (mean, mode, median, and so on) and calculating spread (variance and standard deviation) — you might just want to use Python’s statistics library, which was introduced with Python 3.4.
To use it, import it first, and then you’re good to go! Here’s a session in the Python REPL:
import statistics // Now we can use statistics! data = [20, 30, 30, 40, 40, 40] statistics.mean(data) # 33.333333333333336 statistics.median(data) # 35.0 statistics.mode(data) # 40 statistics.stdev(data) # 8.16496580927726 # Wait, why’s this different from the JavaScript result? # That’s because in Python’s statistics library, # stdev() is the *sample* standard deviation, # while jStat’s stdev() is the *population* standard deviation. # To get the population standard deviation in Python’s statistics, # use pstdev(). statistics.pstdev(data) # 7.453559924999299
Swift: SigmaSwiftStatistics
You can add it to your project in a number of ways:
- Including the SigmaDistrib.swift file into your project.
- Using Carthage.
- Using CocoaPods.
- Using Swift Package Manager.
Here it is in action, in a Swift playground:
let data: [Double] = [20, 30, 30, 40, 40, 40] Sigma.average(data) // 33.333333333333336 Sigma.median(data) // 35 // Oddly enough, there’s no mode function. Sigma.standardDeviationPopulation(data) // 7.453559924999299 Sigma.standardDeviationSample(data) // 8.164965809277259
Kotlin: Kotlin Statistics
If Kotlin’s your jam and you want to do stats, you want Kotlin Statistics.
I use Kotlin primarily in Android Studio, so I use Gradle to include it:
dependencies { compile 'org.nield:kotlin-statistics:1.0.0' }
Here it is, inside an Android app written in Kotlin:
val data = sequenceOf(20, 30, 30, 40, 40, 40) val average = data.average() // 33.333333333333336 val median = data.median() // 35.0 val mode = data.mode() // 40 val standardDeviation = data.standardDeviation() // 7.453559924999299
In the last installment, we laid out the foundation for a simple “notepad”-style app where the user can type in some text, save it with the press of a “Save” button, and then retrieve the saved text of by pressing the “Load” button.
The recap
Here’s what we did in the previous article: we built a simple app with only three controls…
- A text view, where the user enters and edits text,
- A Save button, which will eventually save the text currently in the text view, and
- A Load button, which will eventually retrieve the saved text and put it into the text view.
We applied constraints to the control and wired them up with an outlet and actions as shown below:
At the end of the last article, the Save and Load buttons didn’t save or load — they simply changed the contents of the text view. Clicking the Save button changes the contents of the text view to this:
Here’s the code for the Save button action:
@IBAction func saveButtonPressed(_ sender: UIButton) { userText.text = "You pressed the 'Save' button!" }
Clicking the Load button changes the contents of the text view to this…
…and here’s the code for its action:
@IBAction func loadButtonPressed(_ sender: UIButton) { userText.text = "Ah, the 'Load' button. Nice." }
In this article, we’ll make the Save and Load buttons do what they’re supposed to do: save and load the user’s text.
But before we do that, we need to look at accessing files in iOS.
The iOS filesystem
An iOS app’s access to its iDevice’s filesystem isn’t like the access a desktop application have to its computer’s filesystem. Every iOS app is cordoned off to its own space in the filesystem that only it can access: its sandbox. For two apps — we’ll call them App A and App B — App A’s filesystem access is limited to the App A sandbox, and App B’s is limited to the App B sandbox.
I’ve taken the filesystem sandbox diagram from Apple’s File System Programming Guide and added a few details to it:
For our notepad app, we’re going to store the data that the user types inside a directory in the Data container, which is the part of the sandbox specifically for storing user- and application-related data.
The data container contains a number of subdirectories, one of which is the Documents directory, the designated directory for files that the user will create, import, delete or edit. As an added bonus, unless you specify otherwise, files in this directory are backed up by default.
What we want to do now
We want to change the code in our app’s saveButtonPressed
and loadButtonPressed
methods so that they do the following:
saveButtonPressed
: Take the contents of theuserText
text view and save them in the Documents directory in a file named savefile.txt.loadButtonPressed
: Take the contents of the file named savefile.txt in the Documents directory and put them into theuserText
text view.
Getting our hands on the Documents directory
We’ll store and retrieve our notepad app’s data to and from a file in the Documents directory, which we’ll access with the help of…
- The
FileManager.default
object, which is a one-stop object for working with the file system that should work for most common file system operations, including reading and writing files, and FileManager
’surl
method, which we use to access specific directories in the sandbox. If we pass it a parameter that we want the user’s Documents directory for the app, we get anURL
struct representing the location of that directory.
Here’s code that gets the Documents directory for the current app and stores it in a constant named documentsDirectoryURL
(don’t bother entering this right now):
let documentsDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
What powers this code is the url(for:in:appropriateFor:create:)
method, which can locates and returns the URL for a directory in a given domain. It can even create a directory. It has these parameters:
for
: The directory to search for, which we specify with a value of the enumFileManager.SearchPathDirectory
. In this case, we’re looking for the Documents directory, so we’ll use the valueFileManager.SearchPathDirectory.documentDirectory
, or.documentDirectory
for short.in
: Where to look for the directory, which we specify with a value of the enumFileManager.SearchPathDomainMask
. In this case, we’re searching the user’s filespace, so we’ll use the valueFileManager.SearchPathDomainMask.userDomainMask
, or.userDomainMask
for short.appropriateFor
: This is often used to specify a temporary directory to be created, which we’re not doing here. As a result, we’re simply setting this tonil
, which says “No, we’re not creating a temporary directory”.create
: A boolean value that specifies if the directory should be created if it doesn’t already exist. In this case, we don’t want to do that, so we’ll set this value tofalse
.
Now that we have the URL for the documents directory, we now need an URL for the file where we’ll save and retrieve our notepad data from.
Get the URL for the file we want to save our data in, savefile.txt
Once we have the Documents directory, we can create an URL that refers to a file in that directory by using the URL
struct’s URL(fileURLWithPath:relativeTo:)
method and store it in saveFileURL
(again, don’t bother entering this right now; we’ll do some coding very soon):
let saveFileURL = URL(fileURLWithPath: "savefile.txt", relativeTo: documentsDirectoryURL)
The method has these parameters:
fileURLWithPath
: The name of the file path.relativeTo
: The base URL for the file path. Note that we’re using thedocumentsDirectoryURL
constant that we created in the previous section.
Now let’s enter some code — a computed property that gives us the URL for the file where we want to save data, saveFileURL
. Put this inside the ViewController
class, outside any methods:
private var saveURL: URL { let documentsDirectoryURL = try! FileManager.default.url(for: FileManager.SearchPathDirectory.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) return URL(fileURLWithPath: "savefile.txt", relativeTo: documentsDirectoryURL) }
With this property, we can now make the Save and Load buttons do what they’re supposed to.
Making the Save button save notepad data
Change the saveButtonClicked(_:)
method so that it looks like this:
@IBAction func saveButtonClicked(_ sender: Any) { try! userText.text.write(to: saveURL, atomically: true, encoding: .utf8) }
In our reformulated method, we take the text
property of the userText
text area — an instance of String
that contains the text inside the text area — and use String
’s write(to:atomically:encoding:)
method to write the text
property’s contents to file referenced by our saveURL
computer property. Here’s what the other parameters are for:
atomically
: A boolean, that if set totrue
, has thewrite(to:atomically:encoding:)
method first write the string to a temporary file, and then once done, rename the temporary file to its final name. This ensures that if the iPhone or iPad crashes during thewrite
process, you won’t end up with a corrupted file.encoding
: The way in which the string we’re saving should be encoded, which we specify with a value of the enumString.Encoding
. We want to save the string in the preferred string format of the web, UTF-8, so we’ll use the valueString.Encoding.utf8
, or.utf8
for short.
The Save button now does what it’s supposed to do: save the contents of the text area to a save file.
Making the Load button load saved data
Change the loadButtonClicked(_:)
method so that it looks like this:
@IBAction func loadButtonClicked(_ sender: Any) { do { try userText.text = String(contentsOf: saveURL) } catch { userText.text = "Encountered an error while trying to load saved data." } }
In our reformulated method, we take the text
property of the userText
text area — an instance of String
that contains the text inside the text area — and use String
’s init(contentsOf:)
method to fill it with the contents of the file referenced by our saveURL
computer property. The Load button now does what it’s supposed to do: load the contents of the save file into a text area.
Take a look at your view controller code
The code in ViewController.swift should look like this now:
import UIKit class ViewController: UIViewController { @IBOutlet weak var userText: UITextView! // View controller events // ====================== override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // Save and load button events // =========================== @IBAction func saveButtonClicked(_ sender: Any) { try! userText.text.write(to: saveURL, atomically: true, encoding: String.Encoding.utf8) } @IBAction func loadButtonClicked(_ sender: Any) { do { try userText.text = String(contentsOf: saveURL) } catch { userText.text = "Encountered an error while trying to load saved data." } } private var saveURL: URL { let documentsDirectoryURL = try! FileManager.default.url( for: FileManager.SearchPathDirectory.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) return URL(fileURLWithPath: "savefile.txt", relativeTo: documentsDirectoryURL) } }
If your code looks like this, it’s ready to run.
If you like, you can download the finished project here [37K .zip].
Run the app!
If you’ve followed the steps in this article and the previous one, the app should work as expected. You should be able to:
- Type into the text view.
- Save the contents of the text view by pressing the Save button.
- Change the contents of the text view.
- Restore the contents of the text view to the saved text by pressing the Load button.
Let’s change up the controls whose value we’re saving (or: “What if we changed the text view to a slider?”)
The project that we just covered was the one that I used in the last Tampa iOS Meetup. At the end of the session, one of the attendees asked an interesting question:
“What if we changed the text view to something else? Maybe a slider?”
“Why don’t we give it a try right now?” I replied. “Let’s change the app so that the Save button saves the current position of the slider, and the Load button restores the slider to the saved position.”
I opened Main.storyboard, deleted the text view, and then dragged a slider into its place.
With the slider still selected, I set its constraints as shown above.
Then, I created an outlet for the slider. Using the Assistant Editor, I:
- Deleted the old text view outlet,
- Control-dragged from the slider into ViewController.swift, and
- Gave the outlet the name userValue.
It’s now time to change the code behind the Save and Load buttons.
Making the Save button save the slider position
Here’s the revised saveButtonClicked(_:)
method:
@IBAction func saveButtonClicked(_ sender: Any) { let sliderValue = String(userValue.value) print("Saving slider value: \(sliderValue)") try! sliderValue.write(to: saveURL, atomically: true, encoding: String.Encoding.utf8) }
Here’s what’s happening inside this method:
- We convert the slider’s
value
property — by default, aFloat
whose value can range from 0 (all the way to the left) to 1 (all the way to the right) — and convert it to into aString
. - For debugging’s sake, we print the
String
-ified slider value. - We take the
String
-ified slider value and useString
’swrite(to:atomically:encoding:)
method to write its value to savefile.txt.
Making the Load button restore the slider position
Here’s the revised loadButtonClicked(_:)
method:
@IBAction func loadButtonClicked(_ sender: Any) { do { let sliderValue = try String(contentsOf: saveURL) print("Loading slider value: \(sliderValue)") userValue.value = Float(sliderValue)! } catch { print("Encountered an error while trying to load saved data.") } }
Here’s what’s happening inside this method:
- We take the contents of the file referenced by our
saveURL
computer property and put it inside the constantsliderValue
. - For debugging’s sake, we print
sliderValue
. - We convert
sliderValue
into a Float and use that value to set the position of the slider.
Once again, take a look at your view controller code
The code in ViewController.swift should look like this now:
import UIKit class ViewController: UIViewController { @IBOutlet weak var userValue: UISlider! // View controller events // ====================== override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // Save and load button events // =========================== @IBAction func saveButtonClicked(_ sender: Any) { let sliderValue = String(userValue.value) print("Saving slider value: \(sliderValue)") try! sliderValue.write(to: saveURL, atomically: true, encoding: String.Encoding.utf8) } @IBAction func loadButtonClicked(_ sender: Any) { do { let sliderValue = try String(contentsOf: saveURL) print("Loading slider value: \(sliderValue)") userValue.value = Float(sliderValue)! } catch { print("Encountered an error while trying to load saved data.") } } private var saveURL: URL { let documentsDirectoryURL = try! FileManager.default.url( for: FileManager.SearchPathDirectory.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) return URL(fileURLWithPath: "savefile.txt", relativeTo: documentsDirectoryURL) } }
If your code looks like this, it’s ready to run.
If you like, you can download the finished project here [37K .zip].
What we’ve done so far
In this exercise, we have, over two articles:
- Created a single-view app and added controls to the app’s single view.
- Constrained the controls so that they stay in the proper place, regardless of screen size and orientation.
- Connected the controls to the underlying view controller code using outlets and actions.
- Added code to use the buttons’ actions to respond to being pressed, and to use the text view’s outlet to change its contents.
- Learned about the iOS filesystem.
- Learned how to access the Documents directory in an app’s sandbox.
- Changed the code behind the app’s buttons so that the Save button saves the contents of the text view, and the Load button loads the text view with the saved data.
- Changed the control from a text view to a slider, and made the modifications to the Save and Load button code to save and load the position of the slider.
What now?
If you’re in the Tampa Bay area, come to Tampa iOS Meetup next Tuesday, May 22nd, when I’ll walk you through the process of building a “to-do list” app, and in the process cover:
- Tables, which is how you present lists in iOS,
- the Codable protocol, another way to save data in iOS,
- and finally (and most importantly), getting into the mindset of applying what you know to actually write apps.
After the meetup, I’ll write it up here. Stay tuned!
Other articles in this series
Every week, I compile a list of events for developers, technologists, tech entrepreneurs, and nerds in and around the Tampa Bay area. We’ve got a lot of events going on this week, and here they are!
Monday, May 14
- D&D 5th Edition Riverview/Apollo Beach @ Four Stacks Brewing Company, 6:30 PM to 9:30 PM
- Wesley Chapel Speaks Toastmasters @ Nissan of Wesley Chapel, 6:30 PM to 9:30 PM
- Cool ‘n Confident Toastmasters @ SPC – St. Petersburg/Gibbs Campus, 6:30 PM to 7:45 PM
- Tampa Bay Thinkers — Cryptocurrency: What is it, What’s the Future of it, and Do I want some? @ Carrollwood Cultural Center, 7:00 PM to 9:00 PM
- Largo Board Games Meetup — Kanaban: Automotive Revolution @ 7:00 PM to 10:00 PM
- Fusion 360 Deep Dive (8 Weeks) @ Tampa Hackerspace, 7:00 PM to 10:00 PM
- South Tampa Toastmasters @ Unity of Tampa, 7:00 PM to 8:30 PM
- Nerd Night Out — Retro/Indie Gaming at Brew Bus (Pints & Pixels) @ Brew Bus Brewing, 7:00 PM to 11:00 PM
Tuesday, May 15
- Tampa Small Business Owner Workshops — Free Entrepreneurs Workshop @ Rocky Point Centre, 9:00 AM to 11:00 AM
- Florida Business Analytics Forum 2018 @ University of South Florida Muma College of Business, 11:00 AM to 6:00 PM
- Tampa and Orlando Google Cloud Computing Events — Valliappa Lakshmanan: Machine Learning @ USF Marshall Student Center Ballroom, 12:15 PM to 12:45 PM
- Brandon Boardgamers — Tuesday Night Gaming @ Cool Stuff Games, 5:00 PM to 8:00 PM
- Hacking HR Forum @ The Kaizen Collaborative, 5:30 PM – 8:30 PM
- Tampa SQL User Groups — Pinellas – Don’t Get Lost in Translation: Multilingual Reporting in SSRS @ St Pete College – EpiCenter, 6:00 PM to 9:00 PM
- Game Club Tampa Meetup — Fear Agent: The Open Minded Traveller @ Grand Arena of Mind Expansion, 6:00 PM to 9:00 PM
- Weekly Open Make Night @ Tampa Hackerspace, 6:00 PM to 10:00 PM
- Escape the Grind — The Starting Line @ Buddy Brew – Hyde Park Village, 6:30 PM to 8:00 PM
- Tampa Bay Python — Python Round Table, Salesforce Tampa @ 6:30 PM to 8:30 PM
- Tampa Artificial Intelligence Meetup — AI Study Group Meeting @ Town ‘N Country Regional Public Library, 6:30 PM to 8:00 PM
- Tech4Good Tampa — Skip the Busy Work. Automate it Out. @ Panera Bread, 2285 Ulmerton Rd, Clearwater, 7:00 PM to 10:00 PM
- Upskill Tampa — SEO Tips for Small Businesses @ 7:00 PM to 8:30 PM
- Woodshop Tool Sign Off-Jointer, Planer, & Bandsaw (Members Only) @ Tampa Hackerspace, 7:00 PM to 9:00 PM
- St. Pete Beers ‘n Board Games Meetup for Young Adults @ Flying Boat Brewing Company, 7:00 PM to 10:00 PM
- Portkey to Magic — Supernatural Trivia Night @ Jacks London Grill, 7:00 PM to 9:00 PM
Wednesday, May 16
- OPEN/FREE Coworking for Veteran Entrepreneurs @ FirstWaVE Venture Center, 9:00 AM to 6:00 PM
- 1 Million Cups St. Pete — Marca / Hydroplot @ St. Petersburg Greenhouse, 9:00 AM
- 1 Million Cups Tampa — Florida/Israel Business Accelerator / Wiseshelf @ Entrepreneur Collaborative Center, 9:00 AM
- Tampa Bay Blockchain Developers Meetup — Open code @ Blockspaces, 5:00 PM to 8:00 PM
- Learn Cybersecurity Tampa — Career Convos: John Perkins, vSOC Detect Practice Leader, MSS @ SecureSet Tampa Campus, 5:00 PM to 7:00 PM
- Brandon Blockchain Business and Development Meetup — Come share ideas and listen to experts in the field of blockchain technology. @ Connect Bradenton, 5:30 PM to 6:30 PM
- Tampa Cloud Foundry Meetup — Mark Heckler on Reactive Spring and Cloud Foundry, Masonite’s Ybor city development center, 5:30 PM to 7:00 PM
- Business Process Improvement Professionals Of Tampa Bay — Sofwerx Digital Transformation Summit @ SOFWERX Underground, 5:30 PM to 9:00 PM
- The Suncoast Linux Users Group @ Pinellas Park Public Library, 6:00 PM to 8:00 PM
- Tampa Bay Agile — QA THE AGILE WAY: Assuring your skills “Quality All Fun & Games” @ Keiser University Tampa, 6:00 PM to 8:00 PM
- Grand Gamers of St. Petersburg Board Game Night @ Critical Hit Games, 6:00 PM to 11:30 PM
- Tampa Bay Data Science Group — TBDSG Standard Meeting: Entrepreneurial Opportunities in Data Sciences @ Alessi/Vigo Foods Bacardi Memorial Tasting Room, 6:30 PM to 8:30 PM
- Crypto Investors Club — Panera Bread, 1908 4th Street North, Saint Petersburg, 6:30 PM to 8:30 PM
Thursday, May 17
- Tampa Bay Professionals (IT, Sales, HR & More) — HR PROS- Sustainable Employee Engagement: Fact or Myth @ Online,8:30 AM to 9:00 AM
- Tampa SEO and Internet Marketing Monthly Meetup with Steve Scott @ 6:00 PM to 9:00 PM
- Lean Beer for All Things Agile — Gaspars Grotto, 6:00 PM to 7:30 PM
- WITI – Tampa Bay (Women in Technology International) — Cloud Security @ Nielsen Media Research, 6:00 PM to 8:00 PM
- WordPress St. Petersburg — Ask Us Anything – WordPress Project & Support Crowdsourcing Meetup @ TEC Garage at SPC Downtown Campus, 6:30 PM to 8:30 PM
- BABOK Study/Discussion Groups for Tampa Bay IIBA — South University, 6:30 PM to 7:30 PM
- Bay Area Networking Group — Networking at World of Beer @ World of Beer, 6:30 PM to 8:30 PM
- Functional Suncoast — Learn You a Ramda for Greater Good @ Bank of the Ozarks’ Innovation Lab, 7:00 PM to 9:00 PM
- Fusion 360 Advanced Topics Workshop @ Tampa Hackerspace, 7:00 PM to 10:00 PM
- Suncoast iOS — Fake It Til They Make It – Mocking REST APIs for Building & Testing Clients @ ActSoft, Inc., 7:00 PM to 9:00 PM
- The Tampa Ruby Brigade — Tampa.rb: Tampa Side – Mystery Meetup! @ Andy Beverly School, 7:00 PM to 10:00 PM
Friday, May 18
- Lean Coffee for All Things Agile (Downtown Tampa & Seminole Heights) @ FOUNDATION coffee co., 1607 North Franklin Street, Tampa, 7:30 AM to 8:30 AM
- Café con Tampa @ Oxford Exchange, 8:00 AM to 9:00 AM
- Tampa Cybersecurity Meetup — Capture the Flag: Cybersecurity Hackathon! @ SecureSet Tampa Campus, 6:00 PM to 8:30 PM
- Tampa Monopoly Meetup May Meetup @ Panera Bread, 112 S Westshore, Tampa, 6:45 PM to 9:30 PM
- Tampa Bay Area Software Craftsmanship Meetup — Craftsmanship and Wings @ Lee Roy Selmon’s, 7:00 PM to 10:00 PM
- Pinellas Gamers! — Meet up and Play! @ 10851 Endeavour Way, Seminole, 7:30 PM to 9:30 PM
Saturday, May 19
- Portkey to Magic — Defense Against the Dark Arts Class @ 1:00 PM to 3:00 PM
- Microcontroller Monthly Meetup (M3) @ Tampa Hackerspace, 1:00 PM to 4:00 PM
- Tampa Hackerspace Monthly Board Game Night @ Tampa Hackerspace, 7:00 PM to 11:59 PM
- St. Petersburg “Salon” Discussion Group MeetUp–Theme: NEWS @ 7:00 PM to 9:00 PM
- Kakkoii-Otaku Clan — Deadpool 2 – AMC Veterans 24 @ 7:30 PM to 9:30 PM
Sunday, May 20
“Facebook reportedly plans to launch its own cryptocurrency,” reads The Verge’s headline, followed by the subhead “With an eye towards payments on the social media platform”. My immediate reaction is best summed up with the picture below:
If you missed my two-hour tutorial session on ARKit programming at RWDevCon 2018, Getting Started with ARKit, you’re in luck — you can get the video of the session, along with the slides, step-by-step instructions, and starter and finished code for free!
RWDevCon is an annual conference organized by the people behind RayWenderlich.com, the premier site for mobile app development tutorials. Over three days in early April 2018, the conference featured:
- 4 intensive half-day hands-on workshops, including my in-depth ARKit session,
- 18 hands-on tutorials, including my “Getting Started with ARKit” tutorial included in the free bundle,
- Some very moving inspiration talks, and
- A number of great parties, including one where I got to join the band, James Dempsey and the Breakpoints (who are playing later this year at WWDC)!
My free tutorial, Getting Started with ARKit
Go and download the materials from my tutorial, where you’ll enjoy all sorts of interesting stuff, including gratuitous meme abuse…
…the secret history of augmented reality, including what could be the first literary reference to what would eventually become AR glasses (and written by the author of The Wizard of Oz)…
…what I consider to be some of the best diagrams explaining key ARKit concepts anywhere…
…and a complete walk through the process of building a couple of apps that are both fun to use and show you how to write your own AR apps:
- Happy AR Painter, which you can think of as a less expensive version of Google’s Pixel Brush, but with your iPhone or iPad, and
- Raykea, my tribute to IKEA Place, which lets you see what stuff from my pretend semi-disposable funny-named furniture catalog would look like in your room.
The RWDevCon 2018 Vault
Part of what you get for RWDevCon’s price of admission is the RWDevCon 2018 Vault, which is the next-best thing to being there. It includes:
- Four intensive, half-day workshop videos (including my in-depth ARKit session, where I walk you through building four ARKit apps)
- 18 hands-on tutorial session videos (which includes Getting Started with ARKit)
- Over 500 MB of complete sample project code for all tutorial sessions and workshops
- Over 500 pages of conference instructional workbooks in PDF format
If you didn’t attend RWDevCon 2018 but still want the bundle, you can buy it. Better yet, for a limited time, you can buy it for half price — $99.99 instead of $199.99! (And in case you were wondering, I don’t make any money from sales of the Vault.)
Feeling lucky?
RayWenderlich.com is giving away three copies of the RWDevCon 2018 Vault to three lucky people! Enter the draw by going to this article on their site and leave a comment. On Friday, May 18, they’ll pick three random commenters and give them a free copy of the Vault.