Wednesday, March 20, 2019


  • Did TONS of Seattle trip prep. Weird places to go, cool sights, fun tours, museums, ghost stuff, car, hotel! It was $750 for flights/car/hotel for 4d/3n. Not bad. We'll see how much is added for food/tickets/etc.
  • Groceries and cleaned the whole house: kitchen, bathroom, vacuum, more.
  • Dinner with Alex and Spencer. I miss my dudes! We built a great product in a tough environment.

Tuesday, March 19, 2019

  • Twitch is the external chat client you can embed. I always forget the name so I'm typing it here again.
  • Gbro pooped on the carpet again. The standard pace was too fast, so about 6 weeks ago I slowed it down considerably. I duct taped the center hole fully, then opened it up about half a centimeter every week. Even this proved too much - we're in the 1% here! Holes make cats forget years of bathroom recognition. Giving up and going back to the dome.
  • Did some research in Traeger and Yoder smokers.
  • Went to Bludso's bbq in Hollywood, only a few blocks from Allie's house. Supposedly has some of the best BBQ in LA. I got 1/4lb brisket point, a chicken quarter of dark meat, and 3 spare pork ribs. Overall, I give it a 7. The chicken was the best. The brisket wasn't tender enough for a point, and the bark was underformed. Very small smoke ring. The ribs had great flavor but could have been silkier off the bone. They probably didn't crutch.
  • Filled out two march madness brackets, one for a blake street league and one with the spacex dudes.
  • You can use the <label for="id" ... to make the text on an input checkbox clickable. You can also do it with javascript click events, obviously.
  • SELinux is security-enhanced linux. It's an add-on suite of tools to add security, like disabling network access, etc. It's disabled by default.
  • Besides nginx logs and other app targets, you can always check /var/log/syslog. I forget the obvious sometimes.
  • UFW BLOCK in your syslog is ufw blocking a connection, as it's supposed to. UFW is uncomplicated firewall, ubuntu's built-in.
  • Remember that journalctl also has logs, different from the ones in /var/log.
  • If you type `curl icanhazip.com` you can get your ipv6 address at the command line. Pass -4 for ipv4.
  • If you want to empty a file but keep its location and permissions, run `cat /dev/null > /file/you/want/to/wipe-out`.
  • SC
    • Added winner col to the matchup table and points col to the pick table. Migrated and upgraded.
    • Added leaderboard view! Updated layout, etc.
    • Created a ticket to make the matchups and picks views piggyback on the serverside calculation of winners, rather than doing it clientside: https://github.com/brianmahlstedt/supercontest/issues/33.
    • Wrote Python functions to parse Petty's excel master. One adds (registers) all the users to the User table. The other scrapes all the sheets for each week and adds the picks.
    • Deleted myself and the example users before adding all the 2018 players.
    • Remember, bad transactions will require a rollback() before the same session can be used properly again.
    • Had to do some reverse engineering to figure out how Petty handled duplicate submissions (eg. 5 picks twice) and >5 pick single submissions (he chose the last five, not the first five). This won't be a problem for the app since I enforce it properly, but in order to be accurate in backreference, I made them match.
    • PR, merged, closed ticket #30. Closed the MVP milestone! Moving on to some final items in the next milestone before sending it out for beta.
    • Researched and closed most of the remaining tickets in the "before 2019 season" milestone.
    • Got familiar with flask-assets and flask-cache, for bundling static files and for making expensive routes only run once every N time periods.
    • Spent HOURS trying to resolve issues on the production server. ERR_CONNECTION_REFUSED, site can't be reached. Thought it was nginx, uwsgi, some of my source changes, DNS, digitalocean, reboot, the chrome cache clientside, much more. Checked all logs and many other attempted solutions. Ultimately was certs. Ugh. Just run `sudo certbot --nginx -d southbaysupercontest.com -d www.southbaysupercontest.com` and request/renew new certs (choosing 2 for the https redirect as usual).
    • Some other changes on the production server: Installed xlrd into the venv (which you still have to do with any env changes -_-) and symlinked the service files (which you don't have to do anymore, the links will stay up to date now). Docker will make all this a lot easier.
    • Sent the app to the guys in whatsapp for limited beta testing before forwarding to the whole sbsc email chain.

Monday, March 18, 2019

  • SC
    • Moved the js files around so they're only loaded on the pages that need them.
    • Did the same for css files. Much easier to keep the templates/stylesheets/scripts separate for their various views, consistently named and applied.
    • Added function for get_team_abv for the 3-letter code.
    • Styled the all-picks table. Vertical text was nontrivial.
    • My repo has functional structure currently - an alternative design is divisional structure, where there's a subdir for each route and the static files (templates/js/css) are all alongside it.
    • Closed the blueprint ticket for the next milestone, doing it for the week/picks view nesting. Learned quite a bit here. Reorganized for blueprints.
    • Added a url_value_preprocessor to determine requested_week and available_weeks before passing that information on to the routes in the week blueprint that need it. You're basically just taking it out of the native 'values' dict and putting it into the g object for your own use. Then you don't have to type week<week> in all the routes, and add the week arg to all functions, etc.
    • Added url_defaults as well so that it queries the db for the most recent week on the site's homepage.
    • Organized all the weekX/picks subpages, and added the links for them.
    • Created ticket for the "don't show all picks till sunday" enforcement, to be done at the beginning of next year.
    • Started the LB work.

Sunday, March 17, 2019

  • The template extensions are relative to the template root dir, not local (you have to prepend main/ etc).
  • You can use a <th> tag in place of <td> to get header formatting outside of the header row, like for a left bold column.
  • Stack overflow was offline tonight for maintenance (<1hr).
  • .replace is JS is only for the first occurrence. It's dumb. To replace all, change the first string (the one to change from) "example" to /example/g. You have to remove the quotes, which introduces further dumb requirements. If your string contains special characters, you need to escape them. For example, to remove all periods from an email, you'd do email.replace(/\./g, '').
  • jquery selectors for ID can't have special characters like periods and such.
  • SC
    • Worked on #30, the pick view. Moved templates around to generalize the week header dropdown.
    • Got the pick view basically done. I was surprised how nontrivial it was to handle the table. One of the biggest takeaways: give IDs to all cells in the table, named after the variables (x and y axis headers) passed through jinja. Then jquery can select them easily, rather than trying to find them on the fly.
    • Remaining: some styling, and then generic abstraction of the static content. I basically had views/templates/js for the main table of a week's matchups, but now i need to separate all that for another table so that each has the appropriate scope.

Saturday, March 16, 2019

  • Flask servers persist (or restart after) ubuntu suspension, fyi. If you close your laptop with the app running, it will continue when you reopen.
  • You can have branches in alembic (just like git) for when multiple people are working on changes that modify the models. I accidentally created a branchpoint a while back on the production server. To resolve, you merge the versions (just like git). This creates a new version and migration script (mine was empty, as expected). Then you can migrate and upgrade as usual.
  • For future reference - my net worth exceeded 1m at around age 28. Vested and exercised. Probably age 26 unexercised. The biggest hindrance? Taxes on illiquid assets. AMT traps are real. I paid hundreds of thousands of dollars before even seeing a cent of it. IRC 83(i) will help considerably, but the finance department shucked this novelty due to a clause where purchase offers make employees ineligible. Even...when the purchase offers are inconsistent (nondeterministic schedule), limited (you are severely capped in share sales), unknown (you have no idea when your trap hits), and infrequent (gaps longer than a year apart).
  • The pycharm db browser is buggy if you start manually modifying data.
  • HN
    • Ya, the cookies warnings need to stop.
    • "communicate in the language of options, not demands or preferences" https://news.ycombinator.com/item?id=19349676. I agree. This applies outside the workplace as well. Social issues like racism and other political debates largely stem from personal bias. A withdrawn, impartial view of options and their pros/cons would serve everyone well.
    • This is really cool - basically a sed alternative for find/replace, but with machine learning. https://github.com/Inventitech/strans.
    • The median age of Google/Amazon employees (software in general) is 30. The median age of american workers is 42.
  • Error handlers are pretty easy in Flask. If the exception (or other code, or custom handler) is to be reached in an ajax call, however, you must do something different.
  • SC
    • Removed the backref from the picks table (to users). Left the FK constraint.
    • Removed the points col. This will be a separate table.
    • Added utilities.add_user for easy creation of new users (for testing). This obviously must be invoked from a db context (python manage.py shell), not just any old python console.
    • Created and few users and made sure they were distinct.
    • Moved some test dbs to backups. Merged an old db version, migrated, then upgraded my local dev db.
    • Played with moving html <script> tags around to the proper template to avoid Undefined Variable errors.
    • Did the ajax/flask error handling. If any of the common pick mistakes occur serverside (>5, started game, etc), it will return the traceback and flash the client! All are grouped in the InvalidPicks exception class within the view.
    • Added clientside verification of "game already started" and "can only pick wed-sat". Changed the allowable pick back from status=F to P (the proper one, pregame).
    • Closed ticket #4, created #30 for the last items in the mvp: the pick view and the leaderboard view (then back population from last season's data).
    • Moved the logic for coloring to js (from html). Only applies to picks now, not all.
    • Added an 18th week to the db so that people can play with the pick interface before next season.

Thursday, March 14, 2019

  • PW
    • Watched another tutorial on hidden API manipulation. You really can do some deep inspection with just chrome alone. Adding x-csrf-token headers, scraping for routes, etc. Remember, just run a single get in the same session to grab the token before adding it to headers in subsequent requests. https://www.youtube.com/watch?v=6zge0N962aw.
    • Single page applications, server side rendering, and nuxt.js (for universal vue apps) - https://scotch.io/tutorials/building-a-universal-application-with-nuxtjs-and-django. next.js is React's framework for this.
  • Few small improvements to my bbq game. Ordered a spice dispenser for even rubs, as well as 24" butcher paper for single-sheet wrapping (it was leaking through my separate 12" sheets). Also going to try using the coffee grinder next time for pepper - the hand crank is way too slow.
  • You can access jinja template variables within javascript if you use the html rendering as a proxy. Put this in your template: <script>const myVar = '{{ my_var }}';</script>. This doesn't work if you put it in a separate javascript file, because that isn't rendered.
  • Continued Altered Carbon. While a great show, I still don't like this genre. It's unsatisfying as a viewer to not be able to trust any scene you're presented. It's a deus ex machina on steroids, favoring the show instead of the audience. It's a complexity which hurts the viewer experience rather than adding depth and substance to its plot. Climaxes and resolutions in such worlds aren't clever; they're easy.
  • Template variables are cast into objects (not just strings). This can cause complications between python datatypes and javascript datatypes. Strings are easy. For lists, use the tojson filter {{var|tojson}}. For others, look it up.
  • Multiple elements within the same DOM cannot have the same ID. Use classes to group different elements together, if desired (even if there's no associated styling).
  • SC
    • Worked on commit_picks, parsing the data from the request all the way through writing it to the db.
    • Updated the descriptions on some existing tickets based off new realizations.
    • Serverside and clientside verification of all picks.
    • Emails the user upon pick submission (optionally). Checks and balances, baby. At least until people trust the interface.
    • Changed the table to use classes to group matchup rows and identify the specific columns. Previously, I was using js to find the header and do string matching, or explicitly stating column index. Ridiculous.
    • Handled the submit button logic. Disappears during the ajax call, and reappears if any changes to the picks are made. The user is notified if the picks were committed successfully.

Wednesday, March 13, 2019


  • Blogger's editor uses <br> and <div> tags instead of <p>, hence all the inconsistent formatting in these posts. Sometimes it will inject a newlines at the beginning of a post, sometimes at the end, and sometimes both. It changes all the time, even for a single post that hasn't been edited. Oh well, I can live with this. I've been happy with the other functionality.
  • FW, MD.
  • Registered for the Oct 5 Sonoma tough mudder with Eric!
  • Even if the piece of info is as simple as a single variable, a (hidden) form is still the canonical way to send data to the server. You can do it through ajax, alternatively.
    • If you are using ajax, and you're using flask-wtf csrf protection, you have to send the token (or exempt that route). Incredible help from Martijn Pieters: https://stackoverflow.com/a/22929593.
  • Started watching altered carbon in the background.
  • Supercontest
    • Lots of work on the picks. Played with different methods of sending the pick array to the service. Ultimately went with ajax.
    • Added the csrf token as metadata to the clientside.

Tuesday, March 12, 2019


  • Back from Havasu.
  • Smoked a 10lb pork butt.
  • Verified mileage on all three motorcycles for AAA.
  • Returned Amazon package at Kohl's.
  • Booked Seattle trip with the companion pass for Allie's bday.
  • HN
    • Much better CLI prompts in Python: https://github.com/Mckinsey666/bullet
    • Crunchbase is a cool site that shows lots of internal information about a company. For example, all of SpaceX' funding rounds: https://www.crunchbase.com/organization/space-exploration-technologies/funding_rounds/funding_rounds_list#section-funding-rounds.

Thursday, March 7, 2019

  • Stanford Aero/Astro is starting an alumni newsletter now. There are 17 people in the new aero/astro undergraduate program already! Per Enge died :(
  • I wonder how hard it would be to write a program that parses Ryan’s footage to extract stats like catches and hits. Amazon’s Rekognition tool can do action detection and pathing and such. That would work.
  • Blogger is wayyyy less resource-consuming in chrome than Drive.
  • Caught up on new season of Brooklyn 99. Didn't know it started back up again!
  • Talked to 24 yesterday (Luis). He said that I get a free month but you still have to pay for two months. I assumed that meant that the first month was free, then I could just cancel before paying anything. Sneakily, it meant that you pay for the first and last month, and the middle month is free. I should have pressed harder.
  • Netflix has a heavy ML and experimentation platform. There's a large team working on data science and research. I read their tech blog post about it.
  • To discover private or hidden APIs on a website, just use the network tab of chrome devtools. It will tell you the url routes, the http method, and the data. Then just use it for you own purposes in whatever custom way you want! requests.post(url, data). It can get more complicated with cookies and auth, but you can copy that as well because devtools shows it!
    • A shortcut - just right click the request in devtools and copy it as cURL, or convert it to python, or whatever you want. Very easy export method to repeat requests.
  • sudo apt install gnome-tweaks to get more settings. Removed trash icon, added battery percentage, and a few more small improvements.

Wednesday, March 6, 2019


  • Read a few more Netflix tech blog posts. Encryption, streaming, etc.
  • Read some from Brendan Gregg. Pantastic perf resource http://www.brendangregg.com/.
  • Moved blog to blogger! Better search interface (for my own posts) than Medium. Domain hosted by blogspot (free).
  • Perf records total system activity over a time, then outputs files of the data for something else to analyze. Flamescope is the netflix (open source) tool to visualize this output and determine what was going on. Like a heatmap, it highlights areas of high activity with colors.
  • Periodic railing - could be garbage collection. Periodic idling - could be blocking on i/o, or one thread has a mutex.
  • Strace for system calls/signals, ftrace for kernel function calls, perf for general cpu profiling.

Tuesday, March 5, 2019

  • MySQL is from Oracle.
  • Read an interesting non-binary article that didn’t just discuss gender identity as a new thing, but race identity and age identity. It’s a new perspective to consider trans-gender like trans-race and trans-age.
  • Told Petty about modern db explorers (he was going to build an asp.net application from scratch to read the db lol). Showed him desktop and web versions, lite sqlitebrowser and sqliteonline.
  • Rather than 31+ years, I’ve been alive for 374 months, or 1629 weeks, or 11405 days!
  • Netflix Tech Blog posts.
    • Canary analysis. Deploy new version of software to canary systems to detect bugs. Basically diverting real traffic to a small canary cluster on the side of the production cluster, then comparing metrics and performance.
    • Spinnaker is the continuous delivery stack. They developed it at Netflix, but now it’s used at Google, MS, Amazon, Oracle, many places.
    • Kayenta is the platform that pulls both together. It makes canary deployments autonomous so users don’t have to do these tests manually.
    • Chaosmonkey is public.
    • Public repos!

Monday, March 4, 2019


  • “Disable Cache” is on the network tab of Chrome’s devtools. It only disables the cache while the devtools are open.
  • The em unit is usually the default browser font size.
  • $() is jquery. Much better than the old getElement* syntax.
  • Commas in css selectors means apply the rule to all. Spaces means hierarchy - only applies the rules to the latter elements that are children of the former elements.
  • Css classes aren’t applied in the order you put them on the element, they’re applied in the order they’re defined in the source css document!
  • Removing an element from an array by value is way more complex than it needs to be.
  • Jinja injects newlines stupidly!
  • Remember, var is function-scoped. The new ones for es6, const and let, are block scoped. Const is constant. Let can be reassigned (different than mutable).
  • Supercontest
    • I’m running Bootstrap 3.3.7.
    • Fixed the rounded corners in the table.
    • Smartly added the click functionality, restricted to the team columns, integrated with a submit button.
    • Submit button now smartly appears and disappears based on picks.
    • Used notify.js instead of flash.js to use the less-imposing messages rather than alerts.
    • Warnings appear on >5 picks and opposing-team picks now.

Sunday, March 3, 2019


  • Supercontest
    • The local db was busted so I had to scp it from the prod server and upgrade to the schema with the user table again. Registered my one account to tinker. Copied the db to expedite this if it happens again.
    • Moved the flask_user_layout template to my repo (instead of in the venv flask-user installation) to customize the year and company name, while making everything more consistent. My supercontest layout.html now uses the css classes header-div and clearfix and with-margins and stuff.
    • Remember, if PyCharm is connected to the local db, the app won’t be able to write to it.

Saturday, March 2, 2019


  • Talked with Levi! He’s working at a company called BetterUp. Loves it. Ruby app stack, but still does some Python.
  • Twitch has chat clients that you can embed into your website. Looks to be an easy integration.

Friday, March 1, 2019

  • Checked with Rebecca Balayan, my SpaceX HR coordinator, if I had any outstanding mission patches.
  • Opened the exercise request for my shares. I have 3 days to make the check payment. I’ll send it with Allie or Briley on Monday. Called home and asked for the 30k transfer. BOA has limitations so we may have to wire.
  • There was an $86 charge from 24hr fitness on feb 8. I’ll dispute this back in Hermosa next chance I get.
  • Instead of just instantiating a flask app, having a function return the app is called the “application factory pattern” for future reference.
  • Docker-compose is often used to orchestrate two containers: one for the service and one for the database.
  • Changed my default editor with sudo update-alternatives --config editor.
  • When rebasing, the bottom section of the <<<< ==== >>>> is the newer commit. It will show the hash. The top says head. It’s the older one.
  • When rebasing, “us” is the branch you’re rebasing on (master, usually). “Theirs” is the current branch.
  • HN:
  • Supercontest
    • Deleted branches #2 and #7, they were folded into #3. Rebased #3 and merged. There was some nasty conflicting history. Closed the ticket!
    • Started ticket #4, picks.
    • Created a stripe account to process payments (https://dashboard.stripe.com/test/dashboard). Created a ticket to finish this work later (https://github.com/brianmahlstedt/supercontest/issues/29).

Thursday, February 28, 2019


  • Talked to the Best Buddies coordinators. They do monthly social hours (last thursday of every month at Q’s billiards in West LA. I’m going to go to the next one.
  • Night Crew Labs’ new website! https://www.nightcrewlabs.com/.
  • PW
    • Sklearn has a ton of cool machine learning capability. You can even do data analysis on text, finding correlations and such.
    • WSGI. Request handling and routing is different than application logic.
  • Squarespace is a very popular platform for building websites.
  • Ag will automatically skip folders like venv, so make sure to take that into account when searching for stuff that might be in site-packages.
  • Supercontest
    • Reinstantiated a lot of the flask-user routes. Played with them a bit. Tried to customize most of it by integrating the default forms and such into the navbar of my supercontest page. Ultimately decided against the customization. I can do it later, and right now I want to focus on function rather than style.
    • The navbar at the top is now in an ok place, with home, user, and signout.
    • Played with PyCharm a bit more.
    • SCP is great to move files between. It goes source -> destination. For example, to move the production db to your local dev machine, scp -i mykey southbaysupercontest.com:~/code/supercontest/data/supercontest.db ./test.db.
    • python manage.py db migrate -m “description of change” after you modify the models. Then go to an existing db and python manage.py db upgrade.
    • Pycharm allows you to enter an SQL console on the database in question, which is nice.
    • If you have an existing database with a version that isn’t tracked in the current history (the migrations folder), then internet might tell you to init/migrate/upgrade. This is fine, but it’s a shotgun approach. It’s a wipeover. If you know what version the old database is close to, you can just go into the db and overwrite the value in the alembic_version table, then upgrade as usual.
    • Copied the database over from the production server and upgraded it to the most recent model, which accommodates users and logins.
    • When pycharm is connected to the db, it locks it, so the app can’t write to it. You can disconnect in pycharm with a right-click.
    • The prod database now has a user! Me. I deleted the example user.
    • Aligned the th.

Wednesday, February 27, 2019


  • Played with Pycharm a little bit. Told it which venv/python to use for this project.
  • Supercontest
    • Added instantpage (https://instant.page/) to the main layout. Should speed page load with prefetch. Seems safe.
  • Finished with both seasons of Ozark now.
  • Got lunch with jcriss. Checked out the Redondo Beach Bay Club for the first time.
  • Started reading the book The Four Agreements. I’ve heard good things. Overall, not very impressed. Seemed straightforward.
    • Be impeccable with your word. No gossip. No lies. Pretend you are speaking on live tv at all times.
    • Don’t take anything personally. Other people assume something about you? Ignore it, be yourself, and prove them wrong! This applies to compliments as well as insults.
    • Don’t make assumptions.
    • Always do your best. Take action to enjoy the action, not to expect the reward. Sometimes working twice as many hours won’t mean you get there any faster.
    • Be a child! Be a dog! Explore the world with curiosity and delight.

Monday, February 25, 2019


  • Submitted an application to volunteer with Best Buddies! Honestly teared up a little bit while reading about it.
  • Bought and brined the lamb for tomorrow’s cook. First time smoking lamb! The costco business center has a pretty incredible selection of cuts.
  • Macros: I’d like to aim for something like 100/200/80 for grams of Carb/Protein/Fat, which is a calorie distribution of 20/40/40%. This totals about 2000kCal/day.

Saturday, February 23, 2019


  • Went and saw a live taping of America’s Funniest Home Videos (AFV)! Overall, was a lot of fun. Carlton is the host now. The audience is pretty involved. Comparing this production to my SpaceX webcast production was very interesting. They’re very similar, and I’m thankful to have the experience. Live is very different. Carlton could retake anything that had a mistake.
  • DMV
    • Registered the Ninja as PNO (planned non-operation). It’s no longer insured, as well. $22.
    • Provided proof to the DMV that the BMW is insured. If they detect a vehicle is registered, but not insured, they will suspend the registration. I went online to provide this proof after I received the DMV letter, but AAA had already provided proof of insurance to the DMV, so the website informed me and all was good.

Friday, February 22, 2019


  • HN/PW/M/FW:
  • I could add this blog to my website and host it personally!