- Quadruple-filtered the batch of oat milk today. Made an ok difference. Each time removes a bit of the suspension. Also added 6 pitted dates. Not the biggest change for half a gallon of milk. Gonna save the dates for the next round of protein bars: pecan butter, tahini, oats, dates, protein powder.
- Really interesting story about Nick Diaz' life: https://www.mmafighting.com/2015/9/14/9327767/nick-diaz-opens-old-wounds-on-a-dark-day-in-his-career. Didn't graduate middle school, been fighting all his life. Biggest motivation was his girlfriend killing herself in high school. Now suspended for 5 years for having marijuana in his system. Frustrated that he can't be there for his brother.
- Bought round-trip flight to the bay for the tough mudder, oct 4-7. 15k miles and $11 in fees.
- Significant rework on a lot of vim shortcuts, mostly.
- Use on full tmux terminal for vim, and have vim handle the grid between panes for editing multiple files at once. This allows you to copy between files easily. Then keep other grids in tmux for different shell contexts, like python, bash, psql, git, logs, etc.
- tmux:
- ctrl-a then c to create tab
- ctrl-a then n to move to next tab
- ctrl-a then p to move to previous tab
- ctrl-a then - to split window horizontally
- ctrl-a then \ to split window vertically
- ctrl-a then arrow to move windows
- ctrl-a then x to close window, or tab if no more windows (confirm with y)
- vim:
- ctrl-w then c to create tab (with filetree explorer)
- ctrl-w then n to move to next tab
- ctrl-w then p to move to previous tab
- ctrl-w then - to split window horizontally (with filetree explorer)
- ctrl-w then \ to split window vertically (with filetree explorer)
- ctrl-w then arrow to move windows
- ctrl-w then x to close window, or tab if no more windows
- ctags
- ctrl-] to jump to def
- ctrl-t to jump back
- ctrl-\ to open def in new vim tab
- There's no great way to maximize the current window in vim, like ctrl-a then z does in tmux.
- Good UFC card. Pereira is one of the craziest fighters I have ever seen. So much capoeira. He did a straight backflip on a downed opponent.
- Supercontest.
- Finished updating the core modules for the new db and model structure. Now just need to test with the live app.
- Removed the read/commit from excel from source. This was a one-team use to pull from petty's old data. If I need to reference it again, I can scrape the vcs archives. Nominally it won't be needed ever again.
Saturday, September 14, 2019
Friday, September 13, 2019
- Pay transparency! https://onezero.medium.com/leak-of-microsoft-salaries-shows-fight-for-higher-compensation-3010c589b41e. Leaving your job and coming back into the same role to get a raise...should never be a thing.
- Cool device that closes your windows when a coworker walks in lol: https://github.com/dekuNukem/daytripper.
- Confirmed my plan covers 2 chiro visits per month at all facilities, not each facility. Called Pendergraft, going to buy a 3-visit pack for $90. First appt monday.
- Round trip to the border of hermosa/manhattan, where the street numbers restart, along the strand, is 3.6 miles.
- Ran a 5k (3.1miles). Felt pretty good. A little over 20min.
- Met with Roubik, Stacey, and an engineer from 5m. I liked them, and understand the product uniqueness. I don't know enough about the market to assess their viability and future.
- Got quest bloodwork report back. Everything good except creatinine, slightly higher than the upper limit. Range is 0.60-1.35, I had 1.44. I think this was the same as last time? Electrolytes were good though, I think renal function is fine. False positive due to creatine supplementation, likely.
- Lipid panel was fantastic. Cholesterol numbers solid, even with my weekly meat smoking.
- Import from the distribution name at the toplevel (absolute), but then within each package (__init__, modules) feel free to import relatively. When referencing another package (within the same distribution), go back to absolute imports.
- Supercontest.
- Made all the get_*_picks() queries combine into one. Can query on season, week, or user, modularly. Returns full pick rows.
- Finished going through views, cores, and all other modules to change the db interactions around. Major re-org.
- Always a cool video about encryption and diffie-helman: https://www.youtube.com/watch?v=3QnD2c4Xovk. You just need a function that's easy in one direction and hard in another. Think paint. Easy to determine what two color mix to make, hard to determine what two colors went in a mixture.
- Start with one color. Server and client each have a private color that they mix with the public color. Then send it over. Then mix private color again. Each then has a 3 color mixture of their private, the other's private, and the public color. A third party sniffer knows the combo of each private+public, but doesn't know all 3 because it has never seen the privates without being mixed with the public.
- Instead of paint, a discrete logarithm is usually used. Example: 3^Xmod17. Each party's private is an X. Easy to calculate what that would yield, very hard to figure out what X is if only the answer is known (especially as the numbers get large).
- The n+1 query problem in databases is for one-many relationships (or many-many, as well). You query once for the parent and then n times for the children, which can be very overloading if there are a lot of queries. This is called lazy loading. It's the default for most ORMs. It's faster if the relationships are small.
- The opposite is called eager loading. It's simply a join on the data. For large datasets, it's much faster.
- Flask extension research, again:
- Pagination: https://flask-paginate.readthedocs.io/en/latest/.
- i18n and l10n: https://pythonhosted.org/Flask-Babel/. Don't need it yet with only-californian users, but is very easy to add. Just wrap your app with Babel(app).
- Request tracking: https://matomo.org/. You must have an account with the third-party site, then wrap with Matomo(app, creds) and you can see all your request tracking. https://github.com/Lanseuo/flask-matomo.
- flask-analytics can do it for google analytics, gaug, chartbeat, gosquared, more. https://github.com/citruspi/Flask-Analytics. All report to a third-party.
- Here is another one that collects data and gives an endpoint to your site where it shows! flask-profiler: https://github.com/muatik/flask-profiler.
- Here is another one: https://flask-monitoringdashboard.readthedocs.io/en/latest/functionality.html. This one looks the most comprehensive.
- Error notification: sentry-python! https://github.com/getsentry/sentry-python.
- Airbrake is another exception notifier: https://github.com/airbrake/airbrake-python.
- Tracing: zipkin is the main program. Python has a specific version. And Flask has a specific version: https://github.com/qiajigou/flask-zipkin.
- CORS: https://github.com/corydolphin/flask-cors.
- Webassets: If you want to bundle, minify, and compress all of your html/css/js and simply have jinja only import one file: https://flask-assets.readthedocs.io/en/latest/. Faster, smaller for production.
- Frontend debug toolbar: Same as the one from django: https://flask-debugtoolbar.readthedocs.io/en/latest/. Add this.
- n+1: Will help avoid lazy loading problems. Notifies you when this occurs and tells you to use a join instead: https://github.com/jmcarp/nplusone#flask-sqlalchemy.
- New manhattan softball league started last night.
- France eliminated USA from the FIBA world cup in the quarterfinal lol.
- Supercontest.
- My migration was trying to move scores from lines with UPDATE, but scores is a new table. Needed INSERT INTO. Changed.
- Query for the full leaderboard (without totals) is:
- old models: select season, week, email, sum(points) from picks, users where picks.user_id = users.id group by season, week, email order by season asc, week asc, sum(points) desc;
- new models:
- Lb totals:
- select row_number() over (order by sum(points) desc) as row_number, email, sum(points) from picks, users where picks.user_id = users.id and season = 2019 group by email order by sum(points) desc;
- Without rankings:
- select sum(points) from picks, users where picks.user_id = users.id and season = 2019 group by email order by sum(points) desc;
- Change year as necessary.
- SUM in postgres returns null if the sum is zero, so this only shows people who scored a point over the whole season. You can use max(coalesce(col, 0)) to avoid that.
- Cycled this to test db: restore backup, upgrade, query.
- Quick interim ticket with UI clarifications: https://github.com/brianmahlstedt/supercontest/issues/79
- Highlighting pick capability on the matchups tab.
- Sorting second tier after datetime on matchups. Sorting team abbvs on picks tab.
- LB shows percentage now.
- Niners->Warriors in adspace.
- Made the graph endpoint respect "don't show this week's results until complete" just like the leaderboard does for its colorization. Abstracted that logic out into an initializer for both views.
- Added the INSERTs to the user-season association table in the migration. Everyone goes to 19, a list is crosschecked against 18.
- Made a ticket to remove the src volume in the production app, and bundle all the static content with flask-assets: https://github.com/brianmahlstedt/supercontest/issues/81.
- TNF game was delayed due to lightning. The nfl's xml scoresheet reported back "Suspended" as the status. The app handled it just fine.
- Changed manage.py's shell context to inject the symbols for the model names explicitly, not just the models object. Now you can copy-paste exact queries from the app (db.session.query(User) instead of db.session.query(models.User)).
- Abstracted all interactions with the db to a package called dbsession, with modules `queries` and `commits`. This will make the application side of migrations much easier to update.
- You can incrementally build tables for further querying in sqlalchemy, like you would naturally do with nested SELECT and JOIN statements in SQL. This is super useful for layered relationships, like Pick -> Line -> Week -> Season. The trick is calling .subquery() at the end of your query. Then, you can query it (or join it) later. To access the labelled columns, you use c.
- See supercontest.dbsession.queries for examples.
- You can rename columns with .label('new_name') if you want to change name, deduplicate, or do math and create a new col, etc.
- I'm starting to agree that ORM usage can be way more complicated and abstract than SQL for complex queries.
- All of this model and query redesign made the views module much slimmer. Almost all logic lives outside the routes, which is the way it should be.
- To query on a relationship column, use .has().
- Westgate Supercontest.
- Entry fee is $1500.
- Winner last year was at 70.1%, 59.5 total out of 85 (17*5). He won $1,422, 214.20.
- There were 3,123 contestants for a total of $4,309,740.
- Generated a personal access token for octotree (it uses the free auth for the first X requests).
- In sqlalchemy, use .one() if you expect one and only one result. Returns the object, not a list like .all(). If there might be multiple, use .first(). This won't raise exceptions like .one() will.
- In python dir(var) will give private and dunder attributes, whereas var.__dict__ will just give the main ones (better).
Wednesday, September 11, 2019
- Uber laid off about 8% of its workforce.
- Tax-gain harvesting. Just balancing tax brackets for the year. If your income or investments are lower than usual at some point, then you can sell some of your better stocks (and usually buy them back immediately). Do this to maximize your current income tax bracket (10-12-22-24-32-35-37) and cap gains tax bracket (0-15-20). This allows you to pay a portion of the tax at a time that is cheapest for you.
- The opposite is tax-loss harvesting. If you have stocks that have suffered, and your year had particularly high capital gains, then you can sell them at a loss to offset. Then you buy them back immediately, effectively shifting your basis in that holding to a lower amount.
- Did a little fantasy research to set lineups for this week. Forgot how annoying it was lol. Watching the games is more fun without that stress.
- Bought and smoked a whole octopus.
- $13/lb, 4.7lbs. This was from redondo pier - I'll try an asian market next time, probably a little cheaper.
- Frozen is fine, unlike most poultry/game/cattle. They'll usually have the beak/eyes/guts removed, but do so if the market didn't.
- Let it sit out at room temp for about an hour, with a fan, before cooking. This creates a pellicle - a dried outer layer which smoke can cling to much better than the natural underwater skin.
- Pepper dry rub with maple syrup binder. Mesquite chunks.
- Take to ~140. About 2hrs with the smoker @150.
- Octopus is super low in fats and carbs. Super high in protein and cholesterol.
- They're in the cephalapod class, but above that they're in the mollusk phylum!
- Chopped and prepared all veggies for smoothies and juices.
- SQL.
- Today was almost all SQL.
- You can query distinct on multiple columns, and it will return rows with all the permutations.
- Remember kids, don't hardcode static values into your migrations. If it's based on the current data (moving rows/cols, checking max, etc), but that update infer from the existing data. Also: write and test your downgrades!!
- Foreign keys need definition in the database, and therefore need to be in the alembic migrations. Relationships, however, do not! They're only on the sqlalchemy side, the portion that decides how to write to the db. But the db structure itself, the sql side, does not have knowledge of a "relationship". You still need to define the association tables, foreign keys, etc in the migrations.
- Along the same lines - whether or not the many-many relationship here is unidirectional or bidirectional is purely in the python side as well. The raw db has an association table. That's it. The ORM can choose to reference in both directions on both original tables, or just one.
- Remember, SELECT statements (and subqueries) just return rows. That's why you can pass them to an INSERT statement or likewise. That's also why you can nest them.
- Example join for common supercontest use case:
- select email, team from users inner join picks on users.id = picks.user_id where season = 2019;
- You can be specific about what you want back if the tables share column names:
- select users.id, picks.points from users inner join picks on users.id = picks.user_id;
- Outer join does an inner join first, then checks a condition on one of the tables. Left checks the condition for the first table in the join. Right checks the condition on the second A full outer join does both.
- Cross join does permutations, returning a table with all the columns from both tables in the join.
- Remember, can't add a non-nullable col to existing rows. Needs a default, or add it regular and execute whatever inserts you want, then add the nullable=False constraint last.
- Listing all fk constraints for a table is a long query: https://stackoverflow.com/a/1152321.
- If you do `FROM table1, table2` postgres does an implicit CROSS JOIN, for all permutations. You usually don't want this naked, but often the query comes in the form `FROM table1, table2 WHERE table1.col1 = table2.col2`. This implicitly makes it an INNER JOIN. It's the same syntax as `FROM table1 INNER JOIN table2 on col1 = col2`.
- You can join more than two, as well. Example syntax: `FROM table1, table2, table3`.
- For postgresql and alembic, you have to manually create the sequence in the migration before creating the table:
- from sqlalchemy.schema import Sequence, CreateSequence
- op.execute(CreateSequence(Sequence('groups_field_seq')))
- INSERT INTO requires parentheses around the columns that follow. SELECT should not have parentheses around the multiple values. If you put parentheses, it tries to combine the contents into a compound value.
- Supercontest.
- Small bug in the prod app. sorted_user_ids wasn't defined in the picks view when it's in "only-me" mode wed-sat. It's just your id, one line change.
- Added the week 2 lines. Backed up before and after.
- Verified that "last week" colorizes on the leaderboard now. Verified all the new picking UI functionalities work. The light blue is a great change. The /picks tab shows yours on wed-sat also (only yours).
- Made my picks for this week.
- Overall db change in hierarchy, following foreign keys and relationships:
- Score -> Line -> Week -> Season
- Pick -> Line -> Week -> Season
- Pick -> User
- User -> Season
- Manually created the extensive migration to the new table structure. Some changes were easier: table creation, rename, not nullable, fk, etc. Some changes were harder: conditional updates, moving cols, etc. Practiced a lot of SQL.
- The final migration (just upgrade) was over 100 lines. Not great.
- While you should write downgrades whenever possible, some migrations are not reversible. This is one of them. Data was lost (Pick.points, Matchup.winner, etc). It's not worth recalculating those and programmatically allowing a downgrade. You have backups from before then.
- Got the db to upgrade. Now going to test with sql (manually) and update the app to use the new structure.
- Rebased on the master prod changes.
Tuesday, September 10, 2019
- Supercontest.
- Made the leaderboard current_user row highlight with border like the picks current_user row.
- Standardized all the flask_user templates. Made them extend my bases, so the headers are consistent throughout the whole site.
- Changed all the container/row/cols to be more responsive, and optimized for different viewports.
- Changed the matchups table to white-space:nowrap. This was specifically for the datetime column, but applies to all cols and all rows. Nothing should span two lines. As the viewport shrinks, it should scroll overflow.
- Added make enter-dev/prod-app for ease.
- A recent alembic migration had iteritems(), had to upgrade to items() now that the app is py3.
- Deleted all remote branches and pruned refs.
- Deployed the cosmetic and responsive changes from the first #68 branch.
- Backed up before all prod changes to be sure.
- Migration:
- Pluralized table names for easy querying.
- Dropped default values for user cols: email, is_active, password.
- Made user cols nullable: first_name, last_name.
- Set the val/nextval in the sequences for all 3 tables to match max(id).
- Merged and deployed the changes to the existing db first. Adding new season table and all the others next.
- Made logout tab dynamically change to login based on auth state.
- Gigantic table redesign (full source changes to the model captured here https://github.com/brianmahlstedt/supercontest/commit/0684fdc731d975bbdb80a8a961cc2d83cda1aea2):
- New Season table, with sequence on id. year col, int, not nullable.
- Add seasons col to User table, many-many relationship with Season. Unidirectional.
- New Week table, with seq on id. Two col, season_id (fk), and week. Both ints, both non nullable.
- Rename Matchup to Line table. Include sequence. id, season_id (fk), week_id (fk), favored_team, underdog_team, datetime, line, and home_team moved. The favored_team_score, underdog_team_score, and status cols moved to the new Score table. Winner moved to a new Coverer table. home_team became nullable=False.
- The Pick table lost its season and week cols. It now uses a foreign key to the line table for the id of the matchup that contained the team it picked. Also dropped the points col (did not move). The cols user and line became not nullable.
- New Score table. Id pk with seq. Line_id, fk, int, not nullable. Moved favored_team_score and underdog_team_score and status from the old matchups table here, and made them not nullable.
- I had initially created PickPoints, WeekPoints, and SeasonPoints tables, but I think it's better to recalc than to aggregate and store. This is a design decision based on application usage. Scores can change 3 days out of the 7. If ever a score changes, the points for that pick changes, which requires a recalc of PickPoints, WeekPoints, and SeasonPoints. So storing the calc output doesn't really save much. If you data is more static, then it's better to store the calcs.
- You can customize the graphiql template, but it's not easy. Flask-graphql allows you to pass a template string, but it's a full react app, so you can break it quite easily. I would have to copy over the jumbotron and settings_navs manually, since jinja can't integrate them, so I'll leave it as-is.
- Watched the rob lowe and bruce willis roasts in the background while working. The new alec baldwin roast is coming up this sunday.
- Upgraded the mint link to BoA.
- col, col-12, and col-xs-12 are all the same thing. xs and 12 are the defaults. The breakpoint setting (the viewport size) is, remember, a minimum, so it applies to all screens that are larger. Therefore they all mean one column, across the full width, on all screens.
- Flask-sqlalchemy will autoincrement the first primary key with integer type.
- Coordinated with Roubik (Nel's dad), going to meet Thursday in Glendale.
- A tablespoon of my homemade tahini in a big cup of coffee = delicious. Adds some good fats and a nutty flavor.
- Placed Fresh order.
- Useful psql:
- List all sequences:
- select c.relname from pg_class c where c.relkind = 'S';
- List all defaults:
- select column_name, column_default from information_schema.columns where (table_schema, table_name) = ('public', '<mytable>') order by ordinal position;
- Drop a default:
- alter table public.<table> alter column <column> drop default;
- List cols as nullable or not:
- select table_name, column_name, is_nullable from information_schema.columns where table_name = '<mytable>';
- List indexes:
- select * from pg_index where tablename not like 'pg%';
- Remember, don't execute crucial sql in the database without including it in the alembic upgrades/downgrades. You can put arbitrary op.execute(<sql>) to make sure that all you manual actions are captured programmatically.
- It is understandable, but still kinda sucks how manual db migrations still are. Alembic can't auto-understand every change to your model, especially when abstracted away through an ORM like sqlalchemy, and flask-sqlalchemy.
- Basic relationship patterns: many-one, one-many, one-one, many-many.
- For many-one or one-many, you simply specify a foreign key to another table (usually pulling in the id). If you want actually attribute the whole row (like make all the children available in the parent object), then specify the FK as well as a relationship with back_populates. You can go both directions.
- One-one is easy. It's just many-one or one-many with uselist=False, where you simply attribute a scalar for the parent/child instead of many.
- Many-many isn't that bad. You require an extra table called an association table which connects the column in each of the left and right tables that you want to map. Then you simply reference the association table in each of the two tables you want to associate. You put in both if you want bidirectional (ie child object has parents col and parent obj has a children col), or you can only put it in one if you want.
- I want to smoke a big rib roast next time. This is basically the same meat as the ribeye (the best steak), but in a much larger roast cut instead of a steak cut. Slices of a big rib roast are what prime rib is.
- It is very expensive, obviously. Even a good cheap distributor is gonna charge $15-20/lb for a prime rib roast. Wagyu ribeye can be over $100/lb.
- Costco sells a boneless 7lb for $130.
- Art mentioned biologics and biosimilars: https://www.phrma.org/advocacy/research-development/biologics-biosimilars.
- Did another domain scrape. curebench and pillemporium are both available. I love em.
- When designing the models, you can just put the foreign key IDs without backpopulation/backref. This keeps your tables leaner, but it makes your queries heavier (because you have to join). This is obvious, but is a pretty important decision when designing a system.
Monday, September 9, 2019
- FIBA world cup has finally entered the bracket stage, with only 8 teams left. We play France.
- Filtered my oat milk twice instead of once for the first time day. Made a huge difference.
- Ekeler did a fantastic job yesterday while Gordon continues to cry. Love it.
- Passer rating is basically (touchdowns + yards + completions - interceptions), weighted and normalized by attempts.
- Ranges from 0 to 158.3 (perfect).
- To get perfect, it's basically 12 yd/throw, 80% completion, a touchdown every 10 throws, 0 interceptions.
- Aaran rodgers has the best career passer rating (103.1) and best season (122.5).
- The Equifax data breach settlement continues to disappoint. They now require an additional step from everyone - you must provide proof of an active credit monitoring service to get the <$125 cash, otherwise you only get the free credit monitoring service in the settlement.
- Lost both fantasy matchups this week.
- Remember, a semicolon in js is used to terminate a single statement. Curly braces are blocks that contain statements. If you have an if (condition) {statements} you don't need to terminate with semicolon. If you define a function() {} you don't need to terminate with a semicolon. If you assign and define a function, like const foo = function() {}; then you need to terminate with a semicolon.
- Supercontest.
- Changed it so that calc_lb only does it for the current week, not all in the season. Much faster.
- All current winners and points are now calculated serverside only. It checks the current values and does the math once, then passes matchup.winner and pick.points back to templates as needed. This simplified much of the javascript, since I don't do the duplicated calculation anymore.
- Went back through a lot of the js and terminated statements properly, shifted to 4-sp indentation, etc.
- The /picks tab now respects games that haven't started, coloring them blue.
- All tabs that require current scores (picks, matchups, lb, graph) are much cleaner on the backend, calculating only what's necessary and passing as little as possible through the templates. This required that the lb and graph endpoints got smarter, bc they didn't have the value preprocessor and defaults for week/season.
- The lb is only colorized once a week is completed now.
- Sorted the matchups table by datetime and the picks table alphabetically.
- Deleted the 2018 week 18 fake data.
- Changed the doc onload behavior of coloring picks to a function, called still once onload and then also every time after pick submission. This separation allows submitted picks to be dark blue and unsubmitted to be light blue, which I implemented.
- Tried to make the column headers vertical in the picks table (for team names), but this is unnecessarily difficult in css. Leaving team name abbrvs for now (changed pats to NE).
- Closed https://github.com/brianmahlstedt/supercontest/issues/71.
- My laptop can't find the tv via chromecast half the time. Turning wifi on/off (from my laptop) works, but this is still annoying that chromecast can't flush. I've confirmed they're always on the same network.
- Because of the docker cache, deployments are significantly shorter for smaller changes. To not need to rebuild the image is very timesaving.
- Remember, Python and Javascript have different representations for key/value pairs (dict, hash table). Jinja can handle your python dict just fine, but in order to pass it through a template to js, it needs an interim format that's useful. The most common is json. Dump it in your python app, then have js able to read it.
- data=json.dumps(my_dict) in the route, then myData = {{ data|safe }} in the template.
Sunday, September 8, 2019
- Great day/night with Colin/AK yesterday. Smoked beef ribs and played games at the new apartment then went out on Artesia for shuffleboard/pool.
- In true Cheick Kongo fashion, Cheick Kongo forfeited his title fight in the first round due to an eye poke lol. Ruling was NC, Bader keeps the Bellator HW belt. I have never seen a fighter give up voluntarily like this; they're usually screaming at the doctor and the ref to let them continue. Not doing well for French combat stereotypes.
- First NFL sunday of the season. The best.
- Went 4-1.
- 49ers wons.
- Supercontest behaved perfectly. Picks autopublished at midnight, scores updated in realtime, no issues.
- IT Chapter 2!
- Antonio Brown was released by the Raiders after all the back and forth princess drama. Trying to fight the GM, calling him a cracker, posting on social media about BS fines, apologizing, releasing a youtube video with private phone calls, etc.
- Watched IT chapter 1 to prepare for the new one.
- UFC 242, Khabib vs Poirier.
- Routing/batching/pathplanning software opportunity.
- Talk with Nel's Dad:
- Company name is TSS: https://tssparatransit.com/.
- 5M is the software product: https://tssparatransit.com/paratransit-scheduling-dispatching-software-5m/.
- They receive calls 24 hours beforehand, and then pathplan ~10,000 total drivers and nodes.
- Access, uncle's main company, uses it. https://accessla.org.
- 5M has ~10 software engineers.
- Written in Java.
- They have an onsite server with a backup, but need to move everything to AWS. If it fails, many drivers get stranded.
- They can reroute in semi-realtime, O(minutes)?
- Biggest competitor is Trapeze: https://www.trapezegroup.com/solutions.
- My own research:
- Two APIs for live traffic data:
- https://developer.tomtom.com/products/traffic-api
- https://developer.here.com/documentation/traffic/topics/what-is.html
- TomTom has a routing API as well, which includes realtime traffic, and does many-many, but it is limited to 700: https://developer.tomtom.com/routing-api/routing-api-documentation/batch-routing.
- Most the APIs are the standard pay-as-you-grow, up to about $1 per 1000 transactions.
- It looks like there are actually a ton of products out there for routing and pathplanning, even with batch: https://www.capterra.com/route-planning-software/ and https://www.badgermapping.com/blog/routing-software-small-business-overview-available-choices/.
- OptimoRoute, Locus Dispatcher, WorkWave Route Manager, Wise Systems, ClearDestination, Phalanx, OnFleet, YaCu, Cro, Titanwinds TMS, RouteSavvy, Routific, MobileIQ, C2Logix, MapPoint, Badger Maps...
- Uber obviously has tech for this: https://eng.uber.com/engineering-an-efficient-route/.
- This is a 3-part series about how Lyft achieves the same thing: https://eng.lyft.com/matchmaking-in-lyft-line-9c2635fe62c4.
- And Amazon for its driver deliveries: https://www.technologyreview.com/s/608640/inside-the-increasingly-complex-algorithms-that-get-packages-to-your-door/.
- Overall, I'm wary that a smaller (newer?) product in this space will compete with the big players - or there's a difference in the product and its application/needs that I'm not seeing yet.
- Gonna talk with Stacy, their director, and hopefully an engineer on the team.
- Supercontest.
- Realized that you could technically back out everyone's picks before lockdown with a few queries on the graphql endpoing (via web or python). This is fine for now, I doubt anyone will go through the trouble (the picks table returns id, not name, and you can't filter by season or week directly).
Friday, September 6, 2019
- Researched a pattern for automatic injection of season and week into all db calls. Flask's g object already has season and week from my default value params, but I was hoping there would be a clean pattern where I didn't have to pass them explicitly into every db call. There are some precompile event ways in sqlalchmey, and there's a "BakedQuery" but none do exactly what I wanted. There's no harm in being explicit in every query for now. Once the user table adopts season as well, I might be able to just have a wrapper around db.session.query which inserts season and week everywhere, but it's not important for now. I was surprised a normative solution for this wasn't more common/apparent.
- Sell orders completed in Robinhood. Transferred to BoA.
- Chiro. Feel much better.
- I don't agree with this article: https://abe-winter.github.io/2019/09/03/orms-backwards.html. ORMs are of good convenience to the majority of users, like any high-level abstraction. Most database interactions of not of the complexity/difference that would require raw SQL for integrity.
- Blog.
- In the spirit of retention, I thought it would be a good idea to start a morning habit of rereading my previous blog posts. If I go back a week, this will take about 5 minutes. Every item will be ingrained 7 times, which should be enough to remember most details.
- Changed the main page to only show 7 days, so I just read the whole site every day.
- Redesigned. Simply black now. Better font sizes. Cleaner organization. Removed some gadgets.
- The pgadmin getting started docs are some of the worst I've ever seen. Very verbose, and none of the content I want. How do you install? Give me one sentence with options.
- The web interface allows you some conveniences. You can run the pgadmin server in a container and localhost:5050 gets a web application. You can create users, tables, modify data, etc.
- Any package that requires you to wget a wheel and install it manually is...not going to get any attention. Upload your modules to pypi like a normal human being pls.
- I've been satisfied with psql so far; I'm not going to use pgadmin because of these unnecessary deterrents. PSQL forces me to practice my sql anyway.
- Supercontest.
- Added a repeat-x niners svg to the jumbotron.
- Parsed and put the rules on a new site tab. Used webcomponents and zero-md to convert the md in source to html.
- Closed https://github.com/brianmahlstedt/supercontest/issues/66.
- Started working on the Season table, ticket 68.
- Verified that the remote backup to local, and then restore local from local, correctly syncs the production db to my dev machine.
- Where sqlalchemy would usually have you declare a base, manage the session, etc - flask_sqlalchemy is what I use and it abstracts a lot of that away, simply giving you a db object to do the most common tasks with.
- Met with Art about pharma:
- Recap from my old notes:
- utm params can identify the majority of traffic we generate.
- Universal application to be approved as pharmacy. Standardizing this API would be valuable for everyone, marketplace or not.
- Kayak model: redirect them, don't buy/sell directly. Pros: Simpler. Easier.
- Amazon/Orbitz model: allow buy/sell through our website. Pros: You can generate aggregate purchase orders. Paperwork is a big aspect. You can also hold the money and do a billing cycle.
- Could offer a small client to serve smaller vendor's prices, putting them online.
- Exit strategy is not to monopolize, it's to sell to Amazon (like PillPack for 753m).
- Now actions:
- Build the mvp site.
- Get domain name and host.
- Populate with fake data from multiple vendors. You might be able to get some public data for generics. Some sites even list their rx, like https://auromedics.com/products/ampicillin-and-sulbactam/.
- Write template API that we'll encourage vendors to use. Write client from excel sheet.
- Add basic user login which protects the price comp tool endpoint.
- Add basic landing page which describes the benefits for (a) pharmacies and (b) vendors.
- We are going with the orbitz model, the buy-through-us model. This gives a few benefits:
- One stop shop. One invoice.
- Can include generics, prescriptions, and med supplies in the same order.
- We can basically give credit, where pharmacies can go on a monthly billing cycle, and we pay in the meantime.
- Go speak with vendors. Get them onboard and get their data.
- Here is where you can search for some vendors: https://search.dca.ca.gov/
- Med supply vendors are huge.
- Collect what percentage? Do research, seek financial expertise here.
- Standardized universal application.
- Vendors have to be cool with us giving their data out. This should be fine; it's free marketing.
- Go speak with pharmacies once you have a good selection of vendors and products. Get them to start using it.
- Exit sell to Amazon like PillPack for 753m.
- Met with Nel's dad about the pathplanning app. Notes coming tomorrow after I do more research.
Thursday, September 5, 2019
- Elbow.
- Bloodwork.
- Walk-in, 8am when they opened. Took 45 minutes in the waiting room and 5 minutes of action.
- Made a quest account and downloaded the app, can now check results on my phone when they're ready.
- X-ray.
- Walk-in, 915am a little after they opened. Took 90 minutes in the waiting room and 5 minutes of action.
- Picked up both prescriptions from yesterday.
- Applied the topical painkiller before pull day at the gym. Felt 1000x better. It's incredible how much of a difference it makes. It's incredible how muted my exercise has been for almost 2 years now. Cheers, looking forward to the permanent solution.
- Pinged and finally settled all Hawaii expenses.
- Refilled all powders and pills. Threw a lot out; all that's left is turmeric and glucosamine. Once those are gone, I won't reorder. I eat turmeric root directly and I didn't find much benefit from glucosamine.
- Lamborghini makes an SUV called the Urus. Its MSRP is 200k. Crazy. But, given that 50% of vehicles sales are SUVs nowadays, I get it.
- Homemade protein bars.
- Required ingredients. Just 3. My homemade nut butter, oats, and protein powder. Mix in bowl with rubber spoon then chill in fridge/freezer and cut, or just leave in bowl.
- Optional: Honey, maple, cinnamon, cacao, coconut oil, the usual suspects.
- Now I don't have to buy clif bars for post-gym anymore! That's the very last processed item in my whole diet, now everything is homemade!
- Django crash course (traversy media: https://www.youtube.com/watch?v=e1IyzVyrLSU).
- python manage.py [runserver|migrate|etc] of flask-scripts comes from django.
- Default port 8000.
- Can use jinja, but defaults to django's own template engine (which is really similar anyway).9
- Comes with a lot by default. An admin interface. Gives a skeleton structure for views, models, settings, and more. Creates all the files for you, just leaving you to edit them.
- You can do a lot with django, but I still prefer flask for the most part.
- pgadmin (latest version: 4) is a much better tool for messing with your db than psql. Use it next time.
- Checked mail for the first time in >1mo. Got the replacement amazon card and activated. Also deposited the $14 treasury disbursement (I think it was a settlement from that credit leak?) using mobile checking which was nice.
- The pecans at costco are definitely the cheapest, at ~$8/lb. Bought organic pecans for ~$10/lb (from a company called I'm A Nut) on Amazon, which is worth the convenience of online + organic. This is on regular Amazon, not Fresh.
- Homemade tahini. Just like nut butter, but with seeds. Toast them, then process them. Add a little oil or salt if you want. So good.
- Bought new tupperware. Tired of lidless, wrong-sized options.
- Homemade kava. About 3 tablespoons of root and about half a liter (2 cups) of hot water makes a decent strength individual serving. Mix a little coconut oil in (the fat helps with extraction, just like others), then steep for 10 minutes. Then knead the tea bag.
- Supercontest.
- TNF verifications, first of the season. App behaved very well. Closed https://github.com/brianmahlstedt/supercontest/issues/64.
- There was only one issue. If thursday was picked, it would reject all 5 subsequent picks if you wanted to change one of the other four (which is valid). Fixed it to verify against the current picks.
- Closed the "before 2019 season" milestone.
- Chrome on mobile allows you to create desktop shortcuts from your current page, but that doesn't work when you want the url pre-redirect. The trick to get around it? Disable wifi and mobile data, then the browser can't follow the redirect :) Then create the shortcut from the origin site.
Wednesday, September 4, 2019
- All of my limit sells executed. Should transfer money in a couple days.
- After the all the pushback, zeke signed the biggest RB deal in history. 6yr, 90m. The salary cap in basketball is weird, but the absolute max you can make in a year is about 40m, which is 2-3x higher than football.
- Chiropractor.
- Was awesome. Used a percussion machine instead of manually doing the back cracks. Still did the neck rotation cracks by hand.
- Stretching/cracking at home is fine, as long as you don't go too far or go too jerky.
- I think mine is more of a muscle strain.
- Gonna try valerian root and kava for some natural muscle relaxant. Also gonna ice more.
- Elbow.
- Saw my primary care for a PT + cortisone referral.
- Ended up seeding 4 more appointments:
- X-ray. Called and made one.
- Blood work. Called and made one.
- Then you go back and see primary care for the followup with results.
- Then you get the referral and go to the ortho place for the steroid shot.
- In the meantime, she gave me prescriptions for higher strength pain + anti-inflammatory pills and creams.
- Dropped them off. Came back an hour later to pick up, as instructed. It had been sitting on the counter the whole time; it hadn't started being processed.
- The pharmacist called the doctor a few minutes later to verify the amount (dosage) of anti-inflammatory cream, since it hadn't been written on the rx. The doctor's office was closed, so the verification would have to come the next day and the prescription would be filled tomorrow.
- This is ridiculous. They're going to give me the same tube, no matter what. They just needed something to write for dosage on the tube. I told her to write the smallest dosage possible, achieving the exact conservative goal that such process requirements are meant to enforce. She couldn't.
- This is stupid, but not unexpected from a superfluous workflow that charges 1 hour for something that should take 2 minutes in the first place. Medicine and pharma need more engineers.
- Ordered new running socks (12 pairs) and minimalist running shoes, total $50.
- Cool instance where amex correctly declined a stolen card close to home based on good ML with user spending habits: https://www.reddit.com/r/personalfinance/comments/czt0x2/my_wifes_amex_was_stolen_thieves_attempted_to_use/.
- Supercontest.
- Client.
- Registered an account with pypi and test.pypi. Added ~/.pypirc with both index servers and my creds.
- Created the client package with the query capability. https://github.com/brianmahlstedt/supercontest/issues/61.
- Tested and uploaded to pypi with twine (not devpi) - https://pypi.org/project/supercontest/.
- Westgate finally posted lines for week 1. Updated, tested, and did final season-readiness verifications on https://github.com/brianmahlstedt/supercontest/issues/55.
- Submitted my picks.
- Created a new ticket for tomorrow's live-game tnf verifications (hopefully none): https://github.com/brianmahlstedt/supercontest/issues/64.
- Deployed, talked with petty about email, done.
- LB was being calculated for all games, even ones that hadn't started yet. Shielded the winner and point calculation with status!='P' so that it only calculates started games. It does show the current point totals and leaderboard placement for active games, as if all were ended immediately.
- Since the production app is not started with the uwsgi autoreloader, to ingest new changes you have to run `docker-compose restart supercontest-app-prod`.
- To wipe cells in the production db, do something like `update public.matchup set winner = null where id = XXXX;`.
Tuesday, September 3, 2019
- PMI dropped below 50 for the first time since 2016: https://www.instituteforsupplymanagement.org/ISMReport/MfgROB.cfm.
- A thought experiment that usually helps people with differing opinions see some common perspective: If the world were the size of your block, would you make the same decision?
- Would you still take advantage of that loophole you found in a business, or would you tell the owner because he's your neighbor?
- Would you still invest in that tobacco cart when he's selling to your kids and their friends afterschool?
- All depth charts for all teams and all offensive positions in one page: https://fftoday.com/nfl/depth.php?o=one_page&Side=Off&order_by=.
- Beet stalks/leaves, radish leaves, and cucumbers cannot stay in the dank fridge drawers. They must be kept dry on the racks, or juiced immediately when I cut after delivery.
- Liquidated everything in my robinhood account except MSFT, YUM (KFC, Pizza Hut, Taco Bell), and BYND.
- This includes AMAT, MKSI, LRCX, MSB, TSM.
- Healthcare.
- Created an account on healthnet to find providers. I can now access all my ID numbers, benefits, etc.
- Chiro is covered under ancillary services, which uses an external search provider (ashlink, you can find the link on your profile page). Scheduled an appt with the 4th provider I called.
- Tried to get a PT or sports medicine appointment for the elbow cortisone. The ones I called needed a group referral from my primary care provider. Scheduled an appt with her to get that.
- My copay is $0 for everything, which is great, but overall the experience of finding a provider has been pretty bad. Getting the account set up with the right information to filter options, calling and finding that they actually don't take healthnet, etc.
- I also never received an ID card for healthnet (I did for medi-cal), so I ordered one.
- Got an unsolicited text from a 2020 presidential campaign today. One of the most instant ways to get me not to vote for you.
Monday, September 2, 2019
- Started watching schitt's creek. Good show.
- Horribly verbose article, but centers on an important piece of advice: https://medium.com/better-humans/how-to-read-academic-content-once-and-remember-it-forever-e44f26d82566. After you learn something new, summarize it to yourself every morning for the next week. This will force you to retain the information, it will require that you understand it enough to explain it, it will remind you of the small corners that are easier to forget, allowing you to look them back up, etc.
- Went to Benihana.
- Added the chrome extension "Improved YouTube" - it now defaults to 1.5 speed, removes all ads, and equalizes volume.
- The new meat tenderizer works incredibly. It uses the spike grid instead of just a mallet. Flattened >1lb breasts to under a quarter inch. Smoked curry chicken.
- Blake St. fantasy draft.
Sunday, September 1, 2019
- This channel doodlechaos is so cool: https://www.youtube.com/watch?v=vcBn04IyELc&feature=youtu.be. He syncs classic songs with that line rider game.
- This guy made an hour-long linerider video to an entire instrumental album, wow: https://www.dropbox.com/s/lrfhtik93ismzar/This%20Will%20Destroy%20You%20%5B7-20-17%5D.mp4?dl=0.
- Finance.
- Great article on algorithm trading: https://medium.com/s/story/predicting-the-stock-market-is-easier-than-you-might-think-4f1e0bc05cfe.
- As a nonprofessional trader, your best bet is to follow exactly what the smart money (professionals) are doing. Jump on their trains. You can't outsmart them, and they have a much larger influence on the market.
- Remember, the word for technology in the investment banking + hedge fund profession is FinTech.
- GDP is a fantastic predictor for success.
- ISM = institute for supply management. They publish a monthly index, based on hard data, about how the economy is trending. 50 is neutral, 0 bad, 100 good.
- If it's hovering above 50, that's good and you'll see bull growth in most markets.
- If it's increasing, no matter where it currently is, that's good and you'll see bull growth in most markets.
- If it's hovering below 50, that's bad and you'll see bear decline in most markets.
- If it's decreasing, no matter where it currently is, that's bad and you'll see bear decline in most markets.
- Therefore: Buy when ISM is below 50 but trending upward after a valley. Sell when ISM is above 50 but trending downward after a peak.
- Example report: https://www.instituteforsupplymanagement.org/ISMReport/MfgROB.cfm. This is so useful. Given the current state of slight growth but slowing rate, the advice would be to sell soon when it plateaus.
- PMI = purchasing manager's index. JPMorgan publishes this. It's including in the ISM report. Same general idea.
- There are tons of other css libraries out there for frontend besides bootstrap: bulma, spectre, tailwind, ant, foundation. They're similar: bunch of classes to help lay out and style sites. Most use flexbox for gridding like bootstrap, as well as offering many similar components and utilities. Some are pure cs, some have features that require js and offer a corresponding bundle.
- Added logos to the supercontest readme: https://github.com/brianmahlstedt/supercontest/blob/master/README.md. Took a while (annoyingly) to get the md/html rendering to jive, and I did it on master like an idiot, but it looks much better now. If ever I want to do this on another landing page, it will just be a copy-paste.
- Made walnut butter. Still good, but my least favorite of the nut butters by far.
- Alembic is written by the same guy who wrote SQLAlchemy.
- Solid pier night for wes' farewell yesterday. Saw Dom Mazzetti from broscience at tower 12, said wassup.
- Reread a lot of the bootstrap documentation for tables and forms.
- Supercontest.
- Updated the week_matchups and week_picks templates to use bootstrap tables properly.
- Pale green, light coral, and khaki were the primary colors - now it's table-success, table-danger, and table-warning.
- Added routes and nav buttons for /graphql and /graph, the latter being split from the lb into its own view.
- Added season to the pick and matchup tables. Created two migrations: one for the new col without the NOT NULL constraint, then another to add it. Since the db exists already, you do the first, backfill all the values as desired, then do the second.
- Psql cmmand to write all the values: update public.pick set season=2018; commit;
- Manually edited the alembic migration to do this all in a single version file: add col, set value, add null constraint.
- Flask can't do nested blueprints, so I basically converted week_blueprint to season_week. The matchups and picks routes use both. The leaderboard and graph routes only use season. Added similar url_defaults and value preprocessors for g, where many of the subsequent db queries are dependent on season now.
- Season addition was a lot of work. It was a nontrivial uprooting of most views/templates/models. Every db interaction basically had to be updated to specify season now.
- Reorganized the template hierarchy so that everything wasn't just in layout.html anymore. It's a lot cleaner now, nesting all the nav rows and everything. Each template has a corresponding js file (for the most part).
- Active-navlink logic is universal now. All have the id nav_<route>, then it just inspects window.location.pathname.split('/').includes(id) to add the active class. All navs do this except the week navs, which work slightly differently. They don't just display all available weeks, they display all 17 from the beginning, and disables the ones that aren't available yet. This is because the nested grid, 17>12. It's easier to just lay out the structure and fill it in as it comes, rather than make the html grid nesting dynamic. It distinguishing these ids to loop over by using weeknav_ instead of nav_.
- Added a function is_today() which does the str-int mapping for days of the week. This is already being used for restricting picks wed-sat. I added it to the fetching of scores on the /matchups route as well, so that it only checks the nfl scores if it's a gameday (thurs, sun, mon).
- Ran into some problems because datetime.now() type objects are off in the docker container locally, as well as on the digital ocean droplet. Looks like they're just utc:
- bmahlstedt@bmahlstedt-xps13:~/code/supercontest$ docker-compose exec -T supercontest-app-dev date
- Sun Sep 1 05:18:22 UTC 2019
- bmahlstedt@bmahlstedt-xps13:~/code/supercontest$ docker-compose exec -T supercontest-database date
- Sun Sep 1 05:18:33 UTC 2019
- bmahlstedt@bmahlstedt-xps13:~/code/supercontest$ date
- Sat Aug 31 22:18:39 PDT 2019
- Fixed by adding the following to the dockerfile:
- RUN echo America/Los_Angeles >/etc/timezone && ln -sf /usr/share/zoneinfo/America/Los_Angeles /etc/localtime && dpkg-reconfigure -f noninteractive tzdata
- Flask appends any unused values as query params, so for the lb/graph I had to remove the week info in url_defaults and value_preprocessor. Only need season.
- Switch from nav pills to tabs to better imply hierarchy.
- Closed the season ticket: https://github.com/brianmahlstedt/supercontest/issues/54.
- Changed everyone's name (on the prod db) to properly split first and last.
- Deployed to production.
- Emailed everybody with the new site and instructions. Done! Last items will be wednesday's smoketests when the lines are released.
- The new joker movie is apparently phenomenal. https://www.youtube.com/watch?v=zAGVQLHvwOY.
- Impunity is the same root as punish, immunity from punishment.
- The flask-scripts/python/alembic migrations all operate on a local database, so you have two options: run the commands in the db container or copy the db over and run the commands on the host. In order to do the former, you'd have to bloat the db with system apps like python, so I'm going to do the latter.
- ctrl-t as a vim shortcut for tabs conflicts with ctags' shortcut ctrl-t to jump back a definition. I find the latter more useful.
- zip(*iterableWithNestedIterables) is how you unpack in python! Never knew that was the inverse of itself.
Friday, August 30, 2019
- Retract your bed into the ceiling: https://www.bumblebeespaces.com/.
- The jinja templates have access to the entire g object by default, you don't explicitly need to pass it or its attributes.
- Bootstrap.
- Bootstrap source classes: https://github.com/twbs/bootstrap/blob/master/dist/css/bootstrap-utilities.css (and an analogous file for grid, etc).
- center-block -> mx-auto.
- Great comment on centering options in bootstrap 4: https://stackoverflow.com/a/42559095.
- If you go more than 12 cols, it wraps. There are a few other ways to get around this: nested grids and scrolling.
- "responsive" is such that it updates as your viewport size changes (changing from fullscreen to half, etc). You can specifically use these responsive classes on components like tables, and there are analogs for items like containers (container-fluid).
- Supercontest.
- Fixed the g usage, no longer passing it back to the templating engine. All of the views are 1000x cleaner no. Passing request.url_rule.endpoint for the inferred self blueprint string (like url_for('week.week_picks')) instead of week_link_prefix or switch_link.
- week existed in the url_defaults dict as a key, but was undefined when coming from the lb view, so it didn't look up the max. Changed that to infer the max when either nonexistent OR undefined.
- Restyled EVERYTHING. Removed a lot of my custom css in favor of the bs alternatives.
- A lot of inconsistency was from my usage of bootstrap 4 syntax but with bootstrap 3 compiled css/js in my project vcs. Upgraded, and swapped to cdn usage of bootstrap and notify. Bootstrap requires jquery and popper.
- Added jumbotron for ads at the top.
- Made the syncing nice between 'active' class state for the navlinks. Js basically checks the url and infers what page it's on.
- col-auto for variable width based on content. Changed the name/email nav item to this, in case a name or email is very long. Don't want it to span two lines.
- Renamed the / endpoint to /matchups explicitly. This made the url inference easier to match to the tag ids for active class states.
- no-gutters on the row didn't do exactly what I wanted for the week navs. I nested the grids in a container-fluid for 100% width, then manually set px-0 on the inner cols. Both inner and outer cols had text-center, and both inner and outer rows had justify-content-center. Looks perf now, for all breakpoints.
- Converted the tables to bootstrap. They basically had everything I had written custom in css. So much cleaner.
- In chrome devtools, when inspecting elements, on the css tab: if a property is crossed out, it means that something more specific or something downstream overrode it.
Thursday, August 29, 2019
- Some chargers have a UV bath for sanitizing your phone: https://www.amazon.com/PhoneSoap-Sanitizer-Universal-Patented-Clinically/dp/B072R6MJKQ.
- In Python, you can unpack (destructure) strings as an iterable just like a list!
- Should probably hook my public github apps into travisci at some point.
- Talked with the spacex folks a little bit about investing. Many hold philip morris, which is bullshit, but we talked about recession strategies as well. Some are putting into fixed rate savings accounts @2.5%, which I guarantee I can beat on the public market. My portfolio grew during 07-09. Companies like Netflix, Amazon, Groupon, Lego, and many more all saw between 20-80% annual growth during the last bear.
- APR is a little different, it's the charge.
- The rule of 72: timeToDouble= 72/interestRate So if you want to double your money in ten years, you need to find an annual interest rate of 7.2%.
- two-movies.name is a good alternative for stuff like yesmovies, watchseries, movie4k, etc.
- If any streaming sites go down, this page updates and lists all of them!! https://www.bestfreestreaming.com/
- Vegas odds has the 2019-2020 nba champs at clippers (3.5) lakers (4) bucks (6) rockets (8) 76ers (8) warriors (12).
- Placed fresh order. Trying a ton of new vegetables to juice like radicchio, green cabbage (usually do red), and golden beets (usually do red).
- The Jamie from JRE is Jamie Vernon: http://www.youngjamie.com/. He's a producer/photographer/gamer. His website isn't encrypted lol.
- Started using google calendar more deliberately. Wanted to avoid conflicts like the blake st trip.
- Uninstalled ticktick, no longer need a todo list. Calendar has tasks and I want to keep it all in the same place.
- SpaceX FF draft.
- Bottled kombucha for second fermentation with blueberries. Made new batch.
- Supercontest.
- Talked logistics with petty for a little bit. Gave the creds to the account.
- Created another ticket with some cleanup: https://github.com/brianmahlstedt/supercontest/issues/35.
- Made the sc container names unique to not conflict with bmahlstedt.com.
- Docker system prune (not volumes), reclaiming 13GB lol.
- The password had been wiped on the supercontest db in my local persistent volume. Alter user to fix it, back to what it was before.
- Jinja's |safe filter is what you use to disable all autoescaping. This allows you to do things like pass raw html via python strings to the renderer (similar to a jsx fashion, having html in the app), rather than relying on the template to contain all of the html.
- Removed the week shim, the / home route will run the url_defaults to set the week at the max available.
- Restricted it so that other users' picks for the current week are hidden until midnight on saturday.
- Made the leaderboard, graph, and navbar show first name and last name instead of email. If names aren't present, it defaults back to email.
- Customized the flask-user templates for various things like registration and login. Removed my main/profile and replaced it with the standard user/edit_user_profile. It was just naivete when I first built the app.
- Centered everything, including the feedback route. Styled them all much better and much more consistent. There was a lot of shitty styling, and still is. I've moved bits and pieces over to the proper bootstrap implementation, but there's still a lot of conflict between custom classes and styles.
- Closed https://github.com/brianmahlstedt/supercontest/issues/35.
- Slight bootstrap refresher, since enough time usually passes between UI projects to forget syntax.
- form-group for inputs with other tags. form-control for styling.
- container, row, and col. You can align and justify within. 12 columns. Assign width however you want, and it can be different across different screen sizes. Comes with natural gutters, 15px on each side of each column. You can lay out forms in rows/cols in the same way.
- text-center. <abbr> for hover. <pre> and <code> for code. Variables. User input. nav, navbar (dropdown), jumbotron.
- clearfix should be added to the parent div around floating elements, like float-right or left.
- Pagination, popovers, progress bars, spinners, shadows.
- Width w height h padding p margin m. Margin can go negative (padding can't), so you could have something like mr-lg-n2 which would mean negative right margin on large viewports.
- Screen size callouts apply to that and anything larger. sm > 576px, md > 768px, lg > 992px, xl > 1200px.
Tuesday, August 27, 2019
- eslint-utils>1.4.1 was a critical pin fix. Dependabot submitted PRs for both.
- David Blaine gave a tech talk on how to hold your breath for longer:
- Hyperventilate beforehand (breath in and out very quickly). This purges your body of CO2.
- Full breath in. Don't let any out.
- Don't move at all. Even eyes. Every movement uses oxygen.
- Larger lung capacity is a natural advantage.
- Be in shape. The lower your resting heart rate, the more efficient your oxygen will be.
- Be lighter. The less pounds you carry, the less oxygen you need.
- If you breathe pure O2 (artificially) beforehand, you can hold a lot longer as well.
- During an extreme breathholding attempt, your BPM can drop to ~10. Holyyyyy cow.
- Financial research:
- Feds typically try to keep inflation at about 2% year over year for economic stability. This is a good number to keep in mind for annual raises.
- We are currently in a very long bull market, about 2009-2019. The common definition for a bull market is a 20% swing. So if S&P500 for example hits a low of $1000, then eventually rises to 1200, the bull market will be the time period from that rise until it falls to 1000 again. But it's flexible, bull markets are just general upward trends. There was a long bull market from 1982-2000 (dotcom through y2k). Bear markets are the opposite. These are stupid names. The bull tends to attack upwards whereas the bear swipes downwards.
- Insider sales (executives of big companies selling stock) are often good signs of a swing towards bear. This has been increasing a ton lately (aug saw over 10b sales).
- Yield curve inversion is a comparison of 2yr vs 10yr treasury notes. The longterm note should yield higher interest in a good market, obviously. When it inverts and the 2yr note yields higher interest, it usually means a decline is on its way. The late 20XX recession hit about 2 years after the inversion. Right now, the 2yr is at 1.526% and the 10yr is at 1.479%. The metric here is -4.7 basis points, which is the hundredth-of-percentile difference. This is a really bad inversion.
- The ongoing china trade struggles, tariffs, and presidential tweets are also causing some economic risk.
- All factors above considered, we're very likely headed for bear. Timing is the golden ticket now.
- During recessions, invest in bigger companies. Less risk. Small companies and companies with debt usually do not survive.
- Treasury bonds are one of the safest places to put money before/during a recession. You're effectively loaning the government money and you get paid the interest. This loan is part of the national debt! You can't just buy bonds like shares on the public market, you bid for them.
- Gameplan, I guess: sell some of my smaller holdings and finish the tax burden. If any leftover: bonds or low risk low return big companies.
- Digital ocean sent me an email that they had detected an unsecured mongo instance on my droplet. This is such a cool service - I love it.
- Mongo starts up by default without auth. Any user on the local system can create/delete/read/write. This is how the blog component of my bmahlstedt.com site was set up.
- I would shell into the database (which persists over a docker volume) and add the admin user. Then add a conf file with the creds (gitignore) just like supercontest, and use it within the backend app's docker composition so that it could authenticate when it tries to communicate with the db container. Then you enable auth in the mongo system conf file. https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-mongodb-on-ubuntu-16-04. I chose not to do this, because I don't use the blog.
- A research elephant was given 297mg (that's like 3000 doses) of acid in 1962: https://www.theguardian.com/science/2004/feb/26/research.science.
- Five square puzzle, programmatic solution. http://thinkingames.com/WorkPages/ProductSingle.aspx?pID=5.
- Always check the simple brute force first.
- There are 5^25 permutations of the grid if you ignore rotation and piece constraints. That's 298 quadrillion possibilities, which is way too much to brute force. Even if each grid took 1 microsecond to check, the whole state space would take 1000 years to verify.
- What about if we approach it with the piece-placing route?
- Each 1x2 piece has 20 positions while vertical and 20 positions while horizontal. Then if you count for flipping while in each position, that's 80 positions total. Each 1x3 piece has 15 positions while vertical and 15 positions while horizontal. Then if you count for flipping while in each position, that's 60 positions total.
- There are two 1x2 pieces and seven 1x3 pieces, so we have 80^2*60^7 = 1.79e16. This is 18 quadrillion instead of 298. We're getting a little closer.
- In reality, there are many fewer because as each piece is placed, it increasingly constrains the available positions of the remaining pieces.
- Sounds like we should do a recursive piece-placing strategy, failing fast if any configuration fails?
- Ok but first, ignore the symbols. Let's simply check the permutations for shape placement. Once we have this number N, we can probably brute force. For each shape-constrained grid, we'll have 14*12*10*8*6*4*2*4*2 options, or 5,160,000. The number N shouldn't be too high, there are only so many ways to organize items of length 3 in a 5x5 grid.
- Well let's look at an anchoring strategy for the recursion. This will constrain it even further. No matter the state of the grid, every piece can be considered to have an anchor: its upper-left-most cell. So every grid has 9 anchors. From each anchor, there are only 4 options: 3x1 horizontally, 3x1 vertically, 2x1 horizontally, 2x1 vertically. So we can iterate through each of these permutations, 4^9 = 262,000. Starting in the upper left origin, walk all of these paths with 4 branches at each anchor. This should yield 4x duplicate solutions as well for 90deg rotations, so we expect ~65,000 total iterations to find N from above, N, being a much smaller number because a small percentage of the anchor permutations fit all 9 pieces on the grid.
- There ended up being 164 permutations of shape placements, counting all rotations, which means that N = 41.
- The first attempt at part 2, recursively placing all permutations of the 9 pieces for 5,160,000 options without fail-fast, railed my i5 at 100% cpu for 4 minutes, growing the stack to about 85% of my 4GB of RAM then using the majority of 8GB swap as well. The calculation was not done after 20min, for a single grid of the N=41, so I killed it and proceeded with the validity check after each placement.
- Properly failing fast on part two's recursion yields 32 solutions in ~16s on my i5. This is from N = 164, so we haven't respected rotation yet. The stack is negligible in mem. Once all 32 solutions are known, we could write a programmatic deduplication of the rotation/mirror equivalents, but 32 is small enough to do by hand.
- Solved:
- Put all code in https://github.com/brianmahlstedt/fivesquared.
- Trading bot:
- Created new github repo for this app.
- Wrote my own robinhood api wrapper for transactions, stripped mostly from jamonek. I don't trust third-party code with my financial keys.
- Used yahoo_fin for the inputs. Confirmed they offer live pricing now.
- In py>=3.4, the reload built-in has moved to importlib.reload(). Use `from importlib import reload` then stay the course.
- "Patience is not the ability to wait - it's how we behave while we're waiting." - Joyce Meyer
- If your flow requires break/continue to various layers of loops (more than 1 away), then you need to refactor into functions.
Monday, August 26, 2019
- You have 3 natural cortisol peaks throughout the day, 8-9, 12-1, and 5-6 (approximately). While cortisol is normal regarded as the bad stress hormone, this is only after long-term stress effects. Short-term, cortisol can be regarded as the body's natural upper to increase alertness. Drinking caffeine while the body is already peaking cortisol is not efficient, because then your body starts relying on the external caffeine and reduces internal cortisol production. This is more detrimental than you'd expect - it both REDUCES your natural energy levels and makes you more tolerant of caffeine for external stim. You want to drink caffeine during the cortisol valleys, mid-morning and mid-afternoon. This is like any other drug - take it when you need it, not when the symptoms are absent.
- Smoked a curry pork butt today.
- LD50 is the dose which would be lethal for 50% of people.
- Tons of markets suffered (toys, cars, etc) at the end of last week due to trade wars with China, tariffs, Trump tweets to pull production from China, etc.
- Yes, the gelatin in jello and candy is the same gelatin from rendered animal collagen.
- The yahoo_fin module shows that the live stock prices change on the order of magnitude: seconds. It's not consistent. Sometimes it's one second. Sometimes it's 15 seconds.
- James Randi had a show called exploring psychic powers where he made fools of people who claimed to be psychics: https://www.youtube.com/watch?v=ldr2JTuHBy0.
- Finance research.
- Joined 3 subreddits: r/investing, r/personalfinance, and r/tax.
- SpaceX should be shielded from gigantic market dip, because fundamentally our product has nothing to do with China, and because we're a private company, but unfortunately that's not how the market works. Our valuations will see a decrease from this. I attribute it mainly to how misguided the concept of investment has become. People are not investing because they believe in things, adding value to products they support; they invest as a moneymaking opportunity. They invest for personal financial growth. This lumps the market into a singularity, a big pool representing fluctuating waves of chances, not orthogonal markets representing their respective contributions to society. If investors actually placed money based on virtue, each corner could roller coaster in isolation from the others.
- ETF = exchange traded fund. These are collections of other assets that are grouped to track an index, like the S&P500 ETF does for S&P500.
- "Link in bio" on instagram is annoying af. Just give me the link, don't shamelessly take 4 seconds to self-promote. You're intentionally injecting the equivalent of an ad between the customer and their desired content, causing a bad taste in their mouth before consumption. Not smart.
- New Chappelle standup on Netflix.
Sunday, August 25, 2019
- googlefinance used to be a maintained python wrapper for realtime stock data, but no longer. Yahoo-finance used to be 15min delayed, so it was a lesser option, but now it appears that it offers live prices and is maintained. I'll use yahoo-fin for my bot.
- Joe silva was the longtime matchmaker for the ufc, but now the role is filled by Sean Shelby and Mick Maynard. They're the #2 decisionmakers after Dana.
- Went to an IT-chapter2 themed haunted house last night to promo the upcoming movie. Was awesome.
- Also saw Ready or Not, which was surprisingly good. I had no idea it was half comedy.
- Chipotles, by definition, are just smoked jalepenos. I'll try some with the pork butt tomorrow. They only need to be on for an hour or so.
- Went to Smorgasburg for BBQ day. Finally had Moos. Was very good.
- Andrew luck retired, shocking everyone.
- My amazon visa was declined the past couple times. They didn't have online support, so I called. They card had expired, and they had not sent a replacement. The agent said that was weird - the automated system should have done so already. Got a new one on the way.
- Went to Smorgasburg for the first time. The "row" in the arts district is pretty nice, but the neighboring smorgasburg sector is kinda dumpy. It's a distribution center that has worn forklifts and homeless clutter. They fill it with food stands every sunday and it becomes a nice little food court.
- Moos was there. Overall grade: B+. Satisfied, overall. A- for the actual grade in pitmaster quality, but marked down for the ludicrous prices.
- A. Brisket was very good. Got point only. burnt ends were tasty, good seasoning level. Very tender. Franklins remains untouched, but this comes in shortly after. Light on smoke flavor (i prefer heavy), but light on seasoning (i prefer light) and fantastic on moisture. This is better than my homemade brisket.
- B-. Spare ribs. Decent. Was wrapped too early, because the bark formation was minimal. Not seasoned much at all. My ribs are better.
- C+. Beef ribs. Ok. This cut is hard to screw up because it's so fatty, so the flavor can't really be missed, but the tenderness was average. Doesn't come close to my homemade honey/maple short ribs. I would have given this a B+, but the price was asinine. They charge $56/lb for the regular beef ribs, and $60/lb for the pastrami beef ribs. Absolutely-fuggin-ridiculous. You can get raw short rib, from the plate, prime grade, for $7/lb from a decent distributor.
Subscribe to:
Posts (Atom)



