Compare commits
No commits in common. "main" and "customtheme" have entirely different histories.
main
...
customthem
2
.gitignore
vendored
|
@ -1,6 +1,4 @@
|
|||
tags.*
|
||||
tags
|
||||
cache/
|
||||
.DS_Store
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
3.10
|
|
@ -7,7 +7,7 @@ Python Progress Bar
|
|||
:slug: python-progress-bar
|
||||
:status: published
|
||||
|
||||
I was looking for a nice progress bar today at work to show progress rather than just printing "\ **Waiting 30 seconds…**\ " and having the script do nothing, I wanted to have a progress bar show.
|
||||
I was looking for a nice progress bar today at work to show progress rather than just printing “\ **Waiting 30 seconds…**\ ” and having the script do nothing, I wanted to have a progress bar show.
|
||||
|
||||
I found a progress bar from `Corey Goldberg <http://code.google.com/p/corey-projects/source/browse/trunk/python2/progress_bar.py>`__
|
||||
|
||||
|
@ -17,7 +17,7 @@ newPythonProgressBar [deadlink]
|
|||
|
||||
To use this progressbar, it is very easy.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
# To Setup
|
||||
from progress_bar import ProgressBar
|
||||
|
|
|
@ -9,24 +9,17 @@ Custom Django URLField
|
|||
|
||||
For work I had to write a custom url model field. This model field when setting up accepts a default protocol, and a list of other protocols.
|
||||
|
||||
When checking the protocol, the url is split by "://". If the split has one or two parts, then the url is validly formed.
|
||||
|
||||
In the event of a single element split, there is no protocol specified. When there is no protocol, the url is prepended with the default protocol specified. If there is a protocol, it is checked to make sure it exists in a union of the default protocol and other protocols. If it is not, a ValidationError is raised letting the user know that the protocol is not accepted.
|
||||
| When checking the protocol, the url is split by “://”. If the split has one or two parts, then the url is validly formed.
|
||||
| In the event of a single element split, there is no protocol specified. When there is no protocol, the url is prepended with the default protocol specified. If there is a protocol, it is checked to make sure it exists in a union of the default protocol and other protocols. If it is not, a ValidationError is raised letting the user know that the protocol is not accepted.
|
||||
|
||||
This can all be found at On my github [deadlink].
|
||||
|
||||
I have a couple ways I could have done this better and probably will. Improvements would be just one parameter called parameters in which it is checked if there is at least one element. Passing this, when there is no protocol specified, the first element is the default one.
|
||||
| I have a couple ways I could have done this better and probably will. Improvements would be just one parameter called parameters in which it is checked if there is at least one element. Passing this, when there is no protocol specified, the first element is the default one.
|
||||
| This would be a little cleaner.
|
||||
|
||||
This would be a little cleaner.
|
||||
| this example would allow for http, https, ssh, spdy and mailto, anything else would error out.
|
||||
| ``facebook_page = URLField(default_protocol="http",``
|
||||
| ``protocols=["https","ssh","spdy","mailto"])``
|
||||
|
||||
this example would allow for http, https, ssh, spdy and mailto, anything else would error out.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
facebook_page = URLField(default_protocol="http", protocols=["https","ssh","spdy","mailto"])
|
||||
|
||||
The way I could improve this would be
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
facebook_page = URLField(protocols=["https","https","ssh","spdy","mailto"])
|
||||
| The way I could improve this would be
|
||||
| ``facebook_page = URLField(protocols=["https","https","ssh","spdy","mailto"])``
|
||||
|
|
|
@ -7,47 +7,36 @@ You can un-expire a GPG key.
|
|||
:slug: you-can-un-expire-a-gpg-key
|
||||
:status: published
|
||||
|
||||
Today we had a problem at work on a system.
|
||||
Without getting into too much detail as to give away secrets behind the verbal NDA I am behind, I will just say that it had to do with a GPG public key of mine that was expired on a dev machine, accidentally propagating during install to a production machine.
|
||||
Today we had a problem at work on a system. Without getting into too much detail as to give away secrets behind the verbal NDA I am behind, I will just say that it had to do with a GPG public key of mine that was expired on a dev machine, accidentally propagating during install to a production machine.
|
||||
|
||||
This key had a sub key as well, so figuring out this was tricky.
|
||||
|
||||
To start, you can list your gpg keys like so:
|
||||
To start, you can list your gpg keys like so
|
||||
|
||||
.. code-block:: console
|
||||
``gpg --list-keys``
|
||||
|
||||
$ gpg --list-keys
|
||||
| This will list keys such as
|
||||
| ``pub 4096R/01A53981 2011-11-09 [expires: 2016-11-07]``
|
||||
| ``uid Tyrel Anthony Souza (Five year key for email.)``
|
||||
| ``sub 4096R/C482F56D 2011-11-09 [expires: 2016-11-07]``
|
||||
|
||||
| To make this not expire, (same steps to change expiration date to another time), you must first edit the key
|
||||
| ``gpg --edit-key 01A53981``
|
||||
| You will then see a gpg prompt
|
||||
|
||||
This will list keys such as
|
||||
``gpg>``
|
||||
|
||||
.. code-block:: console
|
||||
| Type “expire” in and you will be prompted for how long to change it to
|
||||
| ``Changing expiration time for the primary key.``
|
||||
| ``Please specify how long the key should be valid.``
|
||||
| `` 0 = key does not expire``
|
||||
| `` <n> = key expires in n days``
|
||||
| `` <n>w = key expires in n weeks``
|
||||
| `` <n>m = key expires in n months``
|
||||
| `` <n>y = key expires in n years``
|
||||
|
||||
pub 4096R/01A53981 2011-11-09 [expires: 2016-11-07]
|
||||
uid Tyrel Anthony Souza (Five year key for email.)
|
||||
sub 4096R/C482F56D 2011-11-09 [expires: 2016-11-07]
|
||||
|
||||
To make this not expire, (same steps to change expiration date to another time), you must first edit the key
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ gpg --edit-key 01A53981
|
||||
|
||||
|
||||
You will then see a gpg prompt ``gpg>``
|
||||
|
||||
Type "expire" in and you will be prompted for how long to change it to
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
Changing expiration time for the primary key.
|
||||
Please specify how long the key should be valid.
|
||||
0 = key does not expire
|
||||
<n> = key expires in n days
|
||||
<n>w = key expires in n weeks
|
||||
<n>m = key expires in n months
|
||||
<n>y = key expires in n years
|
||||
|
||||
You are then done setting the expiration on the primary key, if you have sub key, doing this is as easy as typing ``key 1`` and repeating the expiration step.
|
||||
| You are then done setting the expiration on the primary key, if you have sub key, doing this is as easy as typing
|
||||
| ``key 1``
|
||||
| and repeating the expiration step.
|
||||
|
||||
To finish and wrap things up, type ``save`` and you are done.
|
||||
|
|
|
@ -12,4 +12,4 @@ I am working with txStatsD and Graphite. I was having the hardest problem lookin
|
|||
.. figure:: {static}/images/2012/02/graphite-menu.png
|
||||
:alt: menu in graphite showing draw nonzero as infinite
|
||||
|
||||
This is the option that you must use when you want to mark events. For example we want to know "Server restarted", we would use this technique, as it doesn't make sense to aggregate "server restarted". Using nonzero as infinite is a good way to show an event took place.
|
||||
This is the option that you must use when you want to mark events. For example we want to know “Server restarted”, we would use this technique, as it doesn’t make sense to aggregate “server restarted”. Using nonzero as infinite is a good way to show an event took place.
|
||||
|
|
|
@ -7,19 +7,19 @@ Hubspot
|
|||
:slug: hubspot
|
||||
:status: published
|
||||
|
||||
I was invited to a Hackathon that one of our client's client was throwing. Being that I love programming and learning, I decided I would go.
|
||||
I was invited to a Hackathon that one of our client’s client was throwing. Being that I love programming and learning, I decided I would go.
|
||||
|
||||
The event was in Cambridge, MA. I arrive early, (my friend said there would be a lot more traffic than there was at that time of day) so I got a tour of office. It's situated in an old, what I believe to be, factory building. The coolest part of the office was that they had whiteboard paint on every wall surface, complete with markers of course.
|
||||
The event was in Cambridge, MA. I arrive early, (my friend said there would be a lot more traffic than there was at that time of day) so I got a tour of office. It’s situated in an old, what I believe to be, factory building. The coolest part of the office was that they had whiteboard paint on every wall surface, complete with markers of course.
|
||||
|
||||
The event started and people who were attending had tossed up ideas on the white board. A couple people wanted to integrate LinkedIN with HubSpot. Another person wanted to integrate Eventbrite with HubSpot, to get information to/from event goers after the event ends. I didn't like any of those ideas and my only experience with HubSpot is their Leads API, so I stuck to what I know.
|
||||
The event started and people who were attending had tossed up ideas on the white board. A couple people wanted to integrate LinkedIN with HubSpot. Another person wanted to integrate Eventbrite with HubSpot, to get information to/from event goers after the event ends. I didn’t like any of those ideas and my only experience with HubSpot is their Leads API, so I stuck to what I know.
|
||||
|
||||
I had an idea for an app the second I walked in the door, it was like magic. My main hassle was that HubSpot's Canvas integration REQUIRES HTTPS. Now, my web host is DreamHost and I am kind of cheap, so of course I don't have any way to host a HTTPS site immediately. A big part of me wanted to bite the bullet and order a secure server from DreamHost, or setup another linode, but I felt that I've been spending a lot of money lately and that I would figure out a way. Adrian, my contact at HubSpot, of who I am working with on the PPC project(more on that later), walked by and saved me.
|
||||
I had an idea for an app the second I walked in the door, it was like magic. My main hassle was that HubSpot’s Canvas integration REQUIRES HTTPS. Now, my web host is DreamHost and I am kind of cheap, so of course I don’t have any way to host a HTTPS site immediately. A big part of me wanted to bite the bullet and order a secure server from DreamHost, or setup another linode, but I felt that I’ve been spending a lot of money lately and that I would figure out a way. Adrian, my contact at HubSpot, of who I am working with on the PPC project(more on that later), walked by and saved me.
|
||||
|
||||
He asked if I had ever used GoogleAppEngine. Of course I hadn't because I was under the belief that it cost money to use, but then I realized I was thinking of Amazon's EC2. I sign up for GAE and within an hour I have a HelloWorld site setup. The slow part was installing Python2.5 so I could use the same version that GAE used and not have to fix a lot of backwards compatibility errors between 2.5->2.7.
|
||||
He asked if I had ever used GoogleAppEngine. Of course I hadn’t because I was under the belief that it cost money to use, but then I realized I was thinking of Amazon’s EC2. I sign up for GAE and within an hour I have a HelloWorld site setup. The slow part was installing Python2.5 so I could use the same version that GAE used and not have to fix a lot of backwards compatibility errors between 2.5->2.7.
|
||||
|
||||
After I had a site up that could do HTTPS I dove into programming for my HubSpot app. The app I am doing for work graphs leads per day combined with Google AdWords data per day. I decided to do something different. My app is still a graph, as graphs are fun and easy to understand by everyone.
|
||||
|
||||
This app graphs a set of leads and shows how many leads happened in a given hour for the previous day. Given extra time I would have added an interface to specify the day to graph leads, but last night my time was severely limited by the fact that I had to setup my environment for GoogleAppsEngine.
|
||||
|
||||
Improvements I can and want to do to this app are database, faster processing, and being able to select a date. I almost wanted to break down and learn NodeJS for this, because from my understanding of the event driven nature of NodeJS would be a lot easier to load data over a longer period of time, than to just load it all at once and timeout with HubSpot's Jakarta Commons-HttpClient.
|
||||
Improvements I can and want to do to this app are database, faster processing, and being able to select a date. I almost wanted to break down and learn NodeJS for this, because from my understanding of the event driven nature of NodeJS would be a lot easier to load data over a longer period of time, than to just load it all at once and timeout with HubSpot’s Jakarta Commons-HttpClient.
|
||||
|
||||
|
|
|
@ -7,21 +7,20 @@ Some BASH tips
|
|||
:slug: some-bash-tips
|
||||
:status: published
|
||||
|
||||
I realize I haven't updated in a while. I haven't had much free time recently as I've been working on a project for my father in C# after work hours. This is a great change from only working in Python and JavaScript recently. I'm making a program that will analyze test results from a plasma torch for a company called HyperTherm. My father built the physical machine, but the employees want something that they can better see the results of a passed torch unit, or a failed torch unit. This program has a bar code scanner that scans the tool used in the test and matches it up to the lot of torch parts. Another added feature is the ability to print a white label that says "UNIT PASSED" or a giant red label that says the unit failed and which of the 8 tests failed were.I had to learn how to use delegates, as my serial event listener is on a separate thread and I can't update labels, or parts of the User Interface without them. Still working on it, hopefully will wrap it up by Saint Patrick's day.
|
||||
I realize I haven’t updated in a while. I haven’t had much free time recently as I’ve been working on a project for my father in C# after work hours. This is a great change from only working in Python and JavaScript recently. I’m making a program that will analyze test results from a plasma torch for a company called HyperTherm. My father built the physical machine, but the employees want something that they can better see the results of a passed torch unit, or a failed torch unit. This program has a bar code scanner that scans the tool used in the test and matches it up to the lot of torch parts. Another added feature is the ability to print a white label that says “UNIT PASSED” or a giant red label that says the unit failed and which of the 8 tests failed were. I had to learn how to use delegates, as my serial event listener is on a separate thread and I can’t update labels, or parts of the User Interface without them. Still working on it, hopefully will wrap it up by Saint Patrick’s day.
|
||||
|
||||
I recently found a cool command in BASH that I hadn’t previously known. C-o will execute the current line, and then bring the following line up from BASH history. If you have a set of commands you want to execute again, rather than having to press up 20 times, hit enter, press up 19 times, hit enter, and so on… You can just hit up 20 times. Press C-o as many times as you need to.
|
||||
|
||||
I recently found a cool command in BASH that I hadn't previously known. ``C-o`` will execute the current line, and then bring the following line up from BASH history. If you have a set of commands you want to execute again, rather than having to press up 20 times, hit enter, press up 19 times, hit enter, and so on… You can just hit up 20 times. Press C-o as many times as you need to.
|
||||
| For example
|
||||
|
||||
For example:
|
||||
.. code:: console
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ touch a
|
||||
$ touch b
|
||||
$ touch c
|
||||
tacidsky@ip-234:~$ touch a
|
||||
tacidsky@ip-234:~$ touch b
|
||||
tacidsky@ip-234:~$ touch c
|
||||
# [up] [up] [up]
|
||||
$ touch a [C-o]
|
||||
$ touch b [C-o]
|
||||
$ touch c [C-o]
|
||||
tacidsky@ip-234:~$ touch a [C-o]
|
||||
tacidsky@ip-234:~$ touch b [C-o]
|
||||
tacidsky@ip-234:~$ touch c [C-o]
|
||||
|
||||
As you can see there, all I had to do was go back to the ``$ touch a`` line, and hit control-o three times and it touched the files again!
|
||||
As you can see there, all I had to do was go back to the \`touch a\` line, and hit control-o three times and it touched the files again!
|
||||
|
|
|
@ -9,11 +9,11 @@ Ganymede, Twilio
|
|||
|
||||
Last night I wrote the beginnings of my first NodeJS application. Is application even the correct word?
|
||||
|
||||
I've been meaning to try out the cool API by Twilio, which is used for SMS and VoiceCalling. I decided to design a system that will be two+ endpoints. One is the main server which will listen for UDP messages. When it receives the correct UDP message, configured in the config(`konphyg <https://github.com/pgte/konphyg>`_) files, it will fire off a message to Twilio and send me a text message.
|
||||
I’ve been meaning to try out the cool API by Twilio, which is used for SMS and VoiceCalling. I decided to design a system that will be two+ endpoints. One is the main server which will listen for UDP messages. When it receives the correct UDP message, configured in the config(`konphyg <https://github.com/pgte/konphyg>`_) files, it will fire off a message to Twilio and send me a text message.
|
||||
|
||||
The next steps, which I should be getting to tonight, are to create the Arduino portion and the serial listener. The Arduino will have a button that will send a message over serial to another NodeJS listener. This will decide if the press was good enough, if it passes the debouncing filter, and then fire a message to the main Ganymede server.
|
||||
|
||||
This could be used as a little text message doorbell for when you have your music on too loud. I don't believe I will ever sell this, as it's just for me to get into NodeJS, but It would be fun to share with friends.
|
||||
This could be used as a little text message doorbell for when you have your music on too loud. I don’t believe I will ever sell this, as it’s just for me to get into NodeJS, but It would be fun to share with friends.
|
||||
|
||||
The source so far is located on my github at [DEADLINK].
|
||||
|
||||
|
|
|
@ -6,15 +6,15 @@ Hypertherm
|
|||
:slug: hypertherm
|
||||
:status: published
|
||||
|
||||
For the past three months I have been upgrading and rewriting version 2 of my software for Hypertherm. I am under a contract for my father's company. His company is developing a machine to test how well air flows (laminar flow) through a plasma cutting torch head, and how much air leaks out over a certain time (delta pressure loss).
|
||||
For the past three months I have been upgrading and rewriting version 2 of my software for Hypertherm. I am under a contract for my father’s company. His company is developing a machine to test how well air flows (laminar flow) through a plasma cutting torch head, and how much air leaks out over a certain time (delta pressure loss).
|
||||
|
||||
This has been a nice adventure. I am talking to the tester over serial, reading in a hand scanner (barcodes and acts as a keyboard easy), talking to a DYMO printer and using a database.
|
||||
|
||||
The serial communication was pretty straightforward. I started a new thread and listen for serial all the time. The tricky part with that was that because it was on another thread, I needed a delegate to talk to my UI when I did things like change the picture from blank to a big red X, or update a label.
|
||||
|
||||
The hand scanner wasn't even a factor that took longer than 10 minutes, I just pop up a dialog box asking for input.
|
||||
The hand scanner wasn’t even a factor that took longer than 10 minutes, I just pop up a dialog box asking for input.
|
||||
|
||||
The DYMO printer was the hardest part. This took me a month to figure out, I kept fighting with the printer. I could figure out how to print to the left roll, the ones we setup as as the passing labels, but I couldn't for the life of me figure out how to get it to print to the right label, using a custom label. I tried to load the labels into data and use a StreamWriter/StreamReader object to treat that as the label, but it kept printing one that had, for reasons unknown to me, been locked into the printer. I finally gave up on using the interface they provided and am writing the label to a temporary file. The file is in the user's %appdata% directory in a sub directory that it will not be mistakenly written to, so I feel safe doing it this way. Granted, the machine is a single purpose machine, once this program is installed it will only run this program day and night.
|
||||
The DYMO printer was the hardest part. This took me a month to figure out, I kept fighting with the printer. I could figure out how to print to the left roll, the ones we setup as as the passing labels, but I couldn’t for the life of me figure out how to get it to print to the right label, using a custom label. I tried to load the labels into data and use a StreamWriter/StreamReader object to treat that as the label, but it kept printing one that had, for reasons unknown to me, been locked into the printer. I finally gave up on using the interface they provided and am writing the label to a temporary file. The file is in the user’s %appdata% directory in a sub directory that it will not be mistakenly written to, so I feel safe doing it this way. Granted, the machine is a single purpose machine, once this program is installed it will only run this program day and night.
|
||||
|
||||
Once I got the printer working, I checked it in to github and realized it took me way longer than anticipated. I learned a lot about .NET development (by no means everything, or even most things, just a lot compared to what I did know before [nothing].)
|
||||
|
||||
|
|
|
@ -15,17 +15,15 @@ I think that was the last time I saw him.
|
|||
|
||||
On this Saturday, May 19th, 2012, he was riding his bicycle in North Hampton and collided with a car, sending him flying off and smacking his head on the edge of the curb. There are some other details which I am not 100% sure about. He then was in the hospital until Tuesday May 22, 2012 at which time he passed away.
|
||||
|
||||
We used to talk every day, either on IRC, AIM or gTalk. His account on IRC (no_numbers_here) is still active because his VPS for http://harry.is is still paid for and online until the next billing period. Its so sad seeing his name online and not being able to send a "hey dood" or some other random greeting, then start talking about computers, python, bikes, etc.
|
||||
We used to talk every day, either on IRC, AIM or gTalk. His account on IRC (no_numbers_here) is still active because his VPS for http://harry.is is still paid for and online until the next billing period. Its so sad seeing his name online and not being able to send a “hey dood” or some other random greeting, then start talking about computers, python, bikes, etc.
|
||||
|
||||
Harry was an avid cyclist. I am reading stories that even if he had to go thirty feet, he would hop on his bike to get there. He got me interested in cycling as well. He was going to sell me a bike, but the I was talking to a friend and he gave me on, so I never bought it. Which as it turns out was good as he wanted to give that to his new girlfriend.
|
||||
|
||||
I was planning on hanging out with him next weekend, as he was busy with something this weekend that I can't remember. I wanted to take him target shooting, and wanted to eventually be in enough shape to go hiking with him. None of this ever came to fruition.
|
||||
I was planning on hanging out with him next weekend, as he was busy with something this weekend that I can’t remember. I wanted to take him target shooting, and wanted to eventually be in enough shape to go hiking with him. None of this ever came to fruition.
|
||||
|
||||
Harry Delmolino, we may not have been as close as we could have been, but you definitely made a difference in my life for the better and I never got to thank you for this.
|
||||
|
||||
|
||||
Edit:
|
||||
-----
|
||||
I went to the Calling Hours today and I was only there maybe a half hour, but there were so many people there. It's amazing that a man so young has touched so many lives of so many people, and had accomplished so much. People might say "Oh we was just a kid, he was only 18″ but if they looked at the accomplishments of this young man, they would realize how grown up he was.
|
||||
| Edit:
|
||||
| I went to the Calling Hours today and I was only there maybe a half hour, but there were so many people there. It’s amazing that a man so young has touched so many lives of so many people, and had accomplished so much. People might say “Oh we was just a kid, he was only 18″ but if they looked at the accomplishments of this young man, they would realize how grown up he was.
|
||||
|
||||
I think his mother and father might eventually delete his Facebook, so I went back and took a screenshot of one of our last conversations so I can remember. Everything he said usually warranted a laugh.
|
||||
|
|
|
@ -7,10 +7,10 @@ CFEngine3 Install on CentOS 5.7
|
|||
:slug: cfengine3-install-on-centos-5-7
|
||||
:status: published
|
||||
|
||||
| Today I was tasked with installing CFEngine3 on CentOS-5.7 (A little outdated). When installing CFEngine-3.3.1 I kept getting an error that I couldn't find libtokyocabinet.so.9. I had to set my prefix to /usr/ because the location that tokyocabinet was installing my libraries to was not being read by CFEngine's make script.
|
||||
| Today I was tasked with installing CFEngine3 on CentOS-5.7 (A little outdated). When installing CFEngine-3.3.1 I kept getting an error that I couldn’t find libtokyocabinet.so.9. I had to set my prefix to /usr/ because the location that tokyocabinet was installing my libraries to was not being read by CFEngine’s make script.
|
||||
| To do this (I am using tokyocabinet 1.4.47)
|
||||
|
||||
.. code-block:: console
|
||||
.. code:: console
|
||||
|
||||
wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.47.tar.gz
|
||||
tar -xzvf tokyocabinet-1.4.47.tar.gz
|
||||
|
@ -23,7 +23,7 @@ Then I was able to ./configure && make && make install cfengine3 without any pro
|
|||
|
||||
So my overall script looked something like this:
|
||||
|
||||
.. code-block:: console
|
||||
.. code:: console
|
||||
|
||||
wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.47.tar.gz
|
||||
tar -xzvf tokyocabinet-1.4.47.tar.gz
|
||||
|
@ -32,7 +32,7 @@ So my overall script looked something like this:
|
|||
make
|
||||
sudo make install
|
||||
|
||||
.. code-block:: console
|
||||
.. code:: console
|
||||
|
||||
wget http://cfengine.com/source-code/download?file=cfengine-3.3.1.tar.gz
|
||||
tar -xzvf cfengine-3.3.1.tar.gz
|
||||
|
|
|
@ -7,54 +7,50 @@ Getting started in Python Part 1
|
|||
:slug: getting-started-in-python-part-1
|
||||
:status: published
|
||||
|
||||
I have a friend who is interested in becoming a Python developer. He has some Python experience with CodeAcademy, but he of course wants to take this a step further and develop on his own computer. I figure I'd give him a few pointers, and I know this has been rehashed a million times, but what the hell, why not blog on it again.
|
||||
There are a few important things to learn besides the actual language itself. The first I am going to discuss is has to deal with installing packages, then followed up closely with Python's path trickery. Finally I'm going to wrap up by discussing some software related to development, that could be used for any language, but I use daily in my work as a Python Software Engineer. Let's get started.
|
||||
I have a friend who is interested in becoming a Python developer. He has some Python experience with CodeAcademy, but he of course wants to take this a step further and develop on his own computer. I figure I’d give him a few pointers, and I know this has been rehashed a million times, but what the hell, why not blog on it again.
|
||||
|
||||
There are a few important things to learn besides the actual language itself. The first I am going to discuss is has to deal with installing packages, then followed up closely with Python’s path trickery. Finally I’m going to wrap up by discussing some software related to development, that could be used for any language, but I use daily in my work as a Python Software Engineer. Let’s get started.
|
||||
|
||||
PIP
|
||||
---
|
||||
|
||||
Python is a wonderful language, but how useful would it be if you had to rewrite everything by hand? Not useful at all. That's why the lovely pip developers were born. `PIP <https://pypi.python.org/pypi/pip>`__ (executable pip) is a package manager written for Python. It's very simple to use, and in my opinion is way better than easy_install. To use pip you need to know at a minimum three commands.
|
||||
Python is a wonderful language, but how useful would it be if you had to rewrite everything by hand? Not useful at all. That’s why the lovely pip developers were born. `PIP <https://pypi.python.org/pypi/pip>`__ (executable pip) is a package manager written for Python. It’s very simple to use, and in my opinion is way better than easy_install. To use pip you need to know at a minimum three commands.
|
||||
|
||||
``pip install``
|
||||
| *pip install*
|
||||
| This command does exactly what it says on the box. It queries PyPI (Python Package Index) and downloads the latest version of the package on the server. It then installs it to your site-packages.
|
||||
|
||||
This command does exactly what it says on the box. It queries PyPI (Python Package Index) and downloads the latest version of the package on the server. It then installs it to your site-packages.
|
||||
| *pip uninstall*
|
||||
| This deletes all files associated with the package supplied. 100% simple.
|
||||
|
||||
``pip uninstall``
|
||||
|
||||
This deletes all files associated with the package supplied. 100% simple.
|
||||
|
||||
``pip freeze``
|
||||
This shows what packages are installed on your system and what versions. If you supply ‐‐local it will show what packages are installed in your current environment.
|
||||
These three commands will get you started with package management, there are more commands you can find by looking through the help documents.
|
||||
| *pip freeze*
|
||||
| This shows what packages are installed on your system and what versions. If you supply ‐‐local it will show what packages are installed in your current environment.
|
||||
| These three commands will get you started with package management, there are more commands you can find by looking through the help documents.
|
||||
|
||||
Virtualenv
|
||||
----------
|
||||
|
||||
If you notice I mentioned a current environment in my previous ``pip freeze`` explanation, here is why. Python has a default place that it looks when you reference a package. This is generally in something like ``/usr/lib/python2.7/site-packages/`` or ``C:\Python27\lib``. There is a set of scripts called ``virtualenv`` that creates an environment where you run it with a complete copy of your Python executable, and a blank (unless you copy them over) site-packages directory. You can then install any packages there activate the virtual environment. When activated you use those specific versions, no matter the version of what is installed on your system.
|
||||
| If you notice I mentioned a current environment in my previous *pip freeze* explanation, here is why. Python has a default place that it looks when you reference a package. This is generally in something like **/usr/lib/python2.7/site-packages/** or **C:\\Python27\\lib\\**. There is a set of scripts called *virtualenv* that creates an environment where you run it with a complete copy of your Python executable, and a blank (unless you copy them over) site-packages directory. You can then install any packages there activate the virtual environment. When activated you use those specific versions, no matter the version of what is installed on your system.
|
||||
| Let’s show an example of the first time use of *virtualenv*:
|
||||
|
||||
Let's show an example of the first time use of ``virtualenv``:
|
||||
.. code:: console
|
||||
|
||||
$ sudo pip install virtualenv # Only time you might need sudo, try without first.
|
||||
$ virtualenv myenv # Create the virtual environment
|
||||
$ source myenv/bin/activate # Activate the virtual environment
|
||||
(myenv)$ python -c "import MYPACKAGE; print MYPACKAGE"
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ sudo pip install virtualenv # Only time you might need sudo, try without first.
|
||||
$ virtualenv myenv # Create the virtual environment
|
||||
$ source myenv/bin/activate # Activate the virtual environment
|
||||
(myenv)$ python -c "import MYPACKAGE; print MYPACKAGE"
|
||||
|
||||
Notice how it says your package is not in ``/usr/lib/python2.7/site-packages/`` ? That's because you're using ``virtualenv`` to tell your copied python to use that library instead. There are many reasons you would want to use a virtual environment. The most frequent reason is to preserve version numbers of installed packages between a production and a development environment. Another reason virtualenv is useful if you do not have the power to install packages on your system, you can create a virtual environment and install them there.
|
||||
Notice how it says your package is not in **/usr/lib/python2.7/site-packages/** ? That’s because you’re using *virtualenv* to tell your copied python to use that library instead. There are many reasons you would want to use a virtual environment. The most frequent reason is to preserve version numbers of installed packages between a production and a development environment. Another reason virtualenv is useful if you do not have the power to install packages on your system, you can create a virtual environment and install them there.
|
||||
|
||||
Virtualenvwrapper
|
||||
-----------------
|
||||
|
||||
After you create a virtual environment, you just run``source bin/activate`` and it will activate the virtual environment. This can get tedious knowing exactly where your virtual environments are all the time, so some developers wrote some awesome scripts to fix that problem. This is called``virtualenvwrapper`` and once you use it once, you will always want to use it more. What it does is that it has you create a hidden directory in your home directory, set that to an environment variable and references that directory as the basis for your virtual environments. The installation of this is pretty easy, you can``pip install virtualenvwrapper`` if you want, or download the package and compile by hand.
|
||||
After you create a virtual environment, you just run *source bin/activate*\ and it will activate the virtual environment. This can get tedious knowing exactly where your virtual environments are all the time, so some developers wrote some awesome scripts to fix that problem. This is called *virtualenvwrapper *\ and once you use it once, you will always want to use it more. What it does is that it has you create a hidden directory in your home directory, set that to an environment variable and references that directory as the basis for your virtual environments. The installation of this is pretty easy, you can *pip install virtualenvwrapper* if you want, or download the package and compile by hand. Once installed correctly, you can run the command *mkvirtualenv envname* to create a virtual environment. You can then run *workon envname* from anywhere, and it will activate that environment. For example, you could be at **/var/www/vhosts/www.mysite.com/django/** and run *workon envname* and it would activate the environment from there. This isn’t a required package (none of them are really…) as I went a couple years without using *virtualenvwrapper, *\ but it is very useful and now I use it every day. Some tips I use with my setup of *virtualenvwrapper* is that I use the postactivate scripts to automatically try to change into the proper project directory of my environment. This also means I usually name my *virtualenv * after my project name for easy memory. It makes no sense to have a project called “cash_register” but the *virtualenv* be called “fez”. This is how I change to the right project after activating my *virtualenv.* This goes in **$WORKON_HOME/postactivate**
|
||||
|
||||
Once installed correctly, you can run the command ``mkvirtualenv envname`` to create a virtual environment. You can then run``workon envname`` from anywhere, and it will activate that environment. For example, you could be at``/var/www/vhosts/www.mysite.com/django/`` and run``workon envname`` and it would activate the environment from there. This isn't a required package (none of them are really…) as I went a couple years without using``virtualenvwrapper``, but it is very useful and now I use it every day. Some tips I use with my setup of``virtualenvwrapper`` is that I use the postactivate scripts to automatically try to change into the proper project directory of my environment. This also means I usually name my``virtualenv`` after my project name for easy memory. It makes no sense to have a project called "cash_register" but the``virtualenv`` be called "fez". This is how I change to the right project after activating my ``virtualenv``. This goes in ``$WORKON_HOME/postactivate``
|
||||
|
||||
.. code-block:: bash
|
||||
.. code:: bash
|
||||
|
||||
#!/bin/bash
|
||||
# This hook is run after every virtualenv is activated.
|
||||
|
||||
# if its a work or a personal project (Example)
|
||||
proj_name=$(echo $VIRTUAL_ENV|awk -F'/' '{print $NF}')
|
||||
if [[ -e "/Users/tsouza/PersonalProjects/$proj_name" ]]
|
||||
|
|
|
@ -9,13 +9,14 @@ Help, I have too many Django ManyToMany Queries [FIXED]
|
|||
|
||||
My boss tasked me with getting the load time of 90 seconds(HOLY CARP!) on one page down. First thing I did was install the Django Debug Toolbar to see what was really happening.
|
||||
|
||||
There are currently 2,000 users in the database, the way our model is setup is that a UserProfile can have other UserProfiles attached to it in one of three M2M relations, which in the Django Admin would cause 2,000 queries PER M2M field. This is very expensive as obviously you don't want 10,000 queries that each take 0.3ms to take place.
|
||||
There are currently 2,000 users in the database, the way our model is setup is that a UserProfile can have other UserProfiles attached to it in one of three M2M relations, which in the Django Admin would cause 2,000 queries PER M2M field. This is very expensive as obviously you don’t want 10,000 queries that each take 0.3ms to take place.
|
||||
|
||||
The solution, after a day and a half of research is to override the **formfield_for_manytomany** method in the Admin class for our UserProfile object.
|
||||
|
||||
Our solution is to prefetch for any M2M that are related to the current Model.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
|
||||
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
||||
if db_field.__class__.__name__ == "ManyToManyField" and \
|
||||
|
@ -26,6 +27,6 @@ Our solution is to prefetch for any M2M that are related to the current Model.
|
|||
|
||||
This goes inside our admin class **UserProfileInline(admin.StackedInline)**. Simple clean and easy to drop into another ModelAdmin with minimal changes.
|
||||
|
||||
Other things I pondered was to set all our M2M's as raw_id_fields, then using Select2 or Chosen, query our UserProfiles when the related users were being selected. This would take a lot of load off the initial page load, but is more of a bandaid rather than a real fix.
|
||||
Other things I pondered was to set all our M2M’s as raw_id_fields, then using Select2 or Chosen, query our UserProfiles when the related users were being selected. This would take a lot of load off the initial page load, but is more of a bandaid rather than a real fix.
|
||||
|
||||
I tried to override the Admin class's **def queryset(self, request):** but this was not affecting anything.
|
||||
I tried to override the Admin class’s **def queryset(self, request):** but this was not affecting anything.
|
||||
|
|
|
@ -9,28 +9,28 @@ How to not trigger a post_save in Django, but still modify data.
|
|||
|
||||
Recently I have been diving into using signals with Django, which of course are pretty neat.
|
||||
|
||||
I am working on a website for work which in the most basicexplanation, is a task management site. Recently I have added in the ability to subscribe to tasks and get emails, I did this by connecting to the post_save signal. I only email out when a task is changed, not created (of course, no one would be subscribed to it). This worked flawlessly and "emails" out to anyone who is subscribed. I say that in quotes, because I haven't actually hooked it up to a real SMTP server, and only use
|
||||
I am working on a website for work which in the most basic explanation, is a task management site. Recently I have added in the ability to subscribe to tasks and get emails, I did this by connecting to the post_save signal. I only email out when a task is changed, not created (of course, no one would be subscribed to it). This worked flawlessly and “emails” out to anyone who is subscribed. I say that in quotes, because I haven’t actually hooked it up to a real SMTP server, and only use
|
||||
|
||||
.. code-block:: shell
|
||||
.. code:: console
|
||||
|
||||
python -m smtpd -n -c DebuggingServer localhost:1025
|
||||
python -m smtpd -n -c DebuggingServer localhost:1025
|
||||
|
||||
which will output any emails to stdout. But I digress… A problem arose when I was working on ordering tasks.
|
||||
which will output any emails to stdout. But I digress… A problem arose when I was working on ordering tasks.
|
||||
|
||||
I store an integer in the "ordering" column, which any authenticated user can drag the row to a new location and that will reorder the task. I did this after I setup the emailing signal, so I didn't think about an email being sent out for EVERY task being changed.
|
||||
I store an integer in the “ordering” column, which any authenticated user can drag the row to a new location and that will reorder the task. I did this after I setup the emailing signal, so I didn’t think about an email being sent out for EVERY task being changed.
|
||||
|
||||
I tried a lot of different things, and was debating some that would be a bit messy. Among those ideas were trying to store the past values in another table, but that would get expensive fast. The reason I tried this was because I wanted to see if the ordering was the only thing that changed, and if that was the case, not send an email. I eventually found a thread on StackOverflow that says to use update on the queryset to not trigger the signal.
|
||||
|
||||
You can do this by doing something like this:
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
from app.models import ModelName
|
||||
from app.models import ModelName
|
||||
|
||||
def reorder(request):
|
||||
new_order = request.POST.get('new_order', None)
|
||||
pk = request.POST.get('modelname_pk', None)
|
||||
if new_order:
|
||||
ModelName.objects.filter(pk=pk).update(ordering=new_order)
|
||||
def reorder(request):
|
||||
new_order = request.POST.get('new_order',None)
|
||||
pk = request.POST.get('modelname_pk',None)
|
||||
if new_order:
|
||||
ModelName.objects.filter(pk=pk).update(ordering=new_order)
|
||||
|
||||
I am not sure if this is the proper way save changes and not trigger a post_save signal, but this is the way that worked for me so I figured I would document this.
|
||||
|
|
|
@ -7,9 +7,9 @@ Readline
|
|||
:slug: readline
|
||||
:status: published
|
||||
|
||||
A lot of times when I stop at someone's computer and help them in the terminal, I use a Readline command and people say "How the heck did you do that?"
|
||||
A lot of times when I stop at someone’s computer and help them in the terminal, I use a Readline command and people say “How the heck did you do that?”
|
||||
|
||||
Let me first backup and explain what Readline is. From the GNU Readline Documentation - "The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in." By default, Readline is set up in Emacs mode, no you don't have to have an extra four fingers to use Readline, most of the commands are simple.
|
||||
Let me first backup and explain what Readline is. From the GNU Readline Documentation – “The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in.” By default, Readline is set up in Emacs mode, no you don’t have to have an extra four fingers to use Readline, most of the commands are simple.
|
||||
|
||||
Here are a couple of the commands I use daily:
|
||||
|
||||
|
@ -17,27 +17,26 @@ Here are a couple of the commands I use daily:
|
|||
Movement
|
||||
~~~~~~~~
|
||||
|
||||
- To move to the beginning of a line, you press ``C-a``
|
||||
- To move to the end of a line you press ``C-e``
|
||||
- To move to the beginning of a line, you press **C-a**
|
||||
- To move to the end of a line you press **C-e**
|
||||
|
||||
Killing and Yanking
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- To cut the rest of the line from where your cursor is, to the end, you press ``C-k``
|
||||
- To delete one word you press ``C-w``
|
||||
- To paste either of the two previous back you can press ``C-y``
|
||||
- To cut the rest of the line from where your cursor is, to the end, you press **C-k**
|
||||
- To delete one word you press **C-w**
|
||||
- To paste either of the two previous back you can press **C-y**
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
- To clear the screen and get to a fresh start, you can press ``C-l``
|
||||
- To end your session you can send a ``C-d`` (This will send an end of file character)
|
||||
- To search for a command you typed recently, press ``C-r`` and start typing, it will search backwards. ``C-r`` again will search for an earlier match.
|
||||
- The inverse of ``C-r`` is ``C-s``, they function the same.
|
||||
- To open your ``$EDITOR`` to edit the current shell command you wish to write, press ``C-x C-e``
|
||||
- To clear the screen and get to a fresh start, you can press **C-l**
|
||||
- To end your session you can send a **C-d** (This will send an end of file character)
|
||||
- To search for a command you typed recently, press **C-r** and start typing, it will search backwards. **C-r** again will search for an earlier match.
|
||||
- The inverse of **C-r ** is **C-s**, they function the same.
|
||||
|
||||
Finally, don't forget about ``C-c``. While not specifically Readline, it's very useful because it sends the SIGINT signal to the program, which if just on the command line, will not execute the line you have type, and give you a new line with nothing on it. A nice clean start.
|
||||
Finally, don’t forget about **C-c**. While not specifically Readline, it’s very useful because it sends the SIGINT signal to the program, which if just on the command line, will not execute the line you have type, and give you a new line with nothing on it. A nice clean start.
|
||||
|
||||
To find out a lot more, read the documentation at `the Readline Commands Docs <http://www.gnu.org/software/bash/manual/html_node/Bindable-Readline-Commands.html>`__ I even learned some things while writing this up, apparently pressing ``C-x $`` will list off all the possible usernames. Good to know, and good to always keep learning.
|
||||
To find out a lot more, read the documentation at `the Readline Commands Docs <http://www.gnu.org/software/bash/manual/html_node/Bindable-Readline-Commands.html>`__ I even learned some things while writing this up, apparently pressing **C-x $** will list off all the possible usernames. Good to know, and good to always keep learning.
|
||||
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ First day back in Java since college
|
|||
:slug: java
|
||||
:status: published
|
||||
|
||||
Recently I decided I wanted to learn Java again. I last programmed in Java when I was in College and that was the main language they taught in. I wouldn't say I was a great Java developer, although I completed every Java course well enough to get an A or better.
|
||||
Recently I decided I wanted to learn Java again. I last programmed in Java when I was in College and that was the main language they taught in. I wouldn’t say I was a great Java developer, although I completed every Java course well enough to get an A or better.
|
||||
|
||||
I want to relearn Java because for the past four years I have primarily focused on Python. While it is a great language, I feel I need a change from what I'm focusing on now with primarily web based programming.
|
||||
I want to relearn Java because for the past four years I have primarily focused on Python. While it is a great language, I feel I need a change from what I’m focusing on now with primarily web based programming.
|
||||
|
||||
I decided to refresh myself with Java and read a "Java for Python developers" guide, which was a great refresher. After that I sat around wondering what to program, inspiration wasn't coming quickly. I settled on a SSH Configuration Manager, which is something I've wanted for a while now.
|
||||
I decided to refresh myself with Java and read a “Java for Python developers” guide, which was a great refresher. After that I sat around wondering what to program, inspiration wasn’t coming quickly. I settled on a SSH Configuration Manager, which is something I’ve wanted for a while now.
|
||||
|
||||
This Configuration Manager will read in your ~/.ssh/config files, and show you what hosts you have in a GUI interface. The great part of it will be that you can also create new ssh configurations, without having to remember every little detail. There will be a lot of help tooltips, and pre-fills as well. I have a pretty basic idea of what I want it to look like. Ideally a list on the far left with +/- buttons to add a new Host, and to the right of that will be another hierarchy list of all the key groups you can change, with the most common (that I or people I talk to) being in a "General" or "Common" list. To the right of that will be the actual keys and values you change. I think I would like to be able to "favorite" keys that you use frequently. This way when you create a new host entry, you can quickly fill out your usual configurations be it only adding an IdentityFile and User. Another feature I thought of would be copying/templating, for example being able to create a new "work based server" configuration by just copying one you already have.
|
||||
This Configuration Manager will read in your ~/.ssh/config files, and show you what hosts you have in a GUI interface. The great part of it will be that you can also create new ssh configurations, without having to remember every little detail. There will be a lot of help tooltips, and pre-fills as well. I have a pretty basic idea of what I want it to look like. Ideally a list on the far left with +/- buttons to add a new Host, and to the right of that will be another hierarchy list of all the key groups you can change, with the most common (that I or people I talk to) being in a “General” or “Common” list. To the right of that will be the actual keys and values you change. I think I would like to be able to “favorite” keys that you use frequently. This way when you create a new host entry, you can quickly fill out your usual configurations be it only adding an IdentityFile and User. Another feature I thought of would be copying/templating, for example being able to create a new “work based server” configuration by just copying one you already have.
|
||||
|
||||
Some of the options will be a bit tricky, a couple of them are along the lines of allowing "yes", "no", "ask", or an integer, and I haven't figured out exactly how I want to manage that yet.
|
||||
Some of the options will be a bit tricky, a couple of them are along the lines of allowing “yes”, “no”, “ask”, or an integer, and I haven’t figured out exactly how I want to manage that yet.
|
||||
|
||||
Currently I have a model that only has getters/setters and toString support, there's a lot of them so it's already a 1050 line file last I checked. Next time I work on this project I want to start with data validation and learning how to write tests in Java. I think learning good BDD or TDD habits while learning a "new" language would definitely benefit me.
|
||||
Currently I have a model that only has getters/setters and toString support, there’s a lot of them so it’s already a 1050 line file last I checked. Next time I work on this project I want to start with data validation and learning how to write tests in Java. I think learning good BDD or TDD habits while learning a “new” language would definitely benefit me.
|
|
@ -1,4 +1,4 @@
|
|||
SSH Agent on "boot"
|
||||
SSH Agent on “boot”
|
||||
###################
|
||||
:date: 2015-01-09 04:03
|
||||
:author: tyrel
|
||||
|
@ -20,6 +20,6 @@ I had a friend complain that he had to keep adding his ssh key to his ssh-agent
|
|||
echo "Added key internal to keychain."
|
||||
fi
|
||||
|
||||
This will check every time your bash or zsh rc file is sourced for your key in the currently added keys, and if it's not, it will add it.
|
||||
This will check every time your bash or zsh rc file is sourced for your key in the currently added keys, and if it’s not, it will add it.
|
||||
|
||||
This has the benefit of not requiring you to put in your password every time you connect to a remote machine if you password your ssh keys (which you should).
|
||||
|
|
|
@ -7,4 +7,4 @@ Python Debugger
|
|||
:slug: python-debugger
|
||||
:status: published
|
||||
|
||||
When I worked at Propel Marketing, my dev team used to have presentations on things they loved. I love the Python debugger. It's very useful and I believe a proper understanding of how to use a debugger, will make you a better programmer. Here is a presentation on the debugger I made for my team. https://prezi.com/cdc4uyn4ghih/python-debugger/
|
||||
When I worked at Propel Marketing, my dev team used to have presentations on things they loved. I love the Python debugger. It’s very useful and I believe a proper understanding of how to use a debugger, will make you a better programmer. Here is a presentation on the debugger I made for my team. https://prezi.com/cdc4uyn4ghih/python-debugger/
|
||||
|
|
|
@ -7,14 +7,14 @@ Too many open files
|
|||
:slug: too-many-open-files
|
||||
:status: published
|
||||
|
||||
When I worked at Propel Marketing, we used to outsource static websites to a third party vendor, and then host them on our server. It was our job as developers to pull down the finished website zip file from the vendor, check it to make sure they used the proper domain name, (they didn't a lot of the time,) and make sure it actually looks nice. If these few criteria were met, we could launch the site.
|
||||
When I worked at Propel Marketing, we used to outsource static websites to a third party vendor, and then host them on our server. It was our job as developers to pull down the finished website zip file from the vendor, check it to make sure they used the proper domain name, (they didn’t a lot of the time,) and make sure it actually looks nice. If these few criteria were met, we could launch the site.
|
||||
|
||||
Part of this process was SCPing the directory to our sites server. The sites server was where we had Apache running with every custom static site as a vhost. We would put the website in ``/var/www/vhosts/domain.name.here/`` and then create the proper files in sites-available and sites-enabled (more on this in another entry). After that the next step was to run a checkconfig and restart Apache.
|
||||
Part of this process was SCPing the directory to our sites server. The sites server was where we had Apache running with every custom static site as a vhost. We would put the website in /var/www/vhosts/domain.name.here/ and then create the proper files in sites-available and sites-enabled (more on this in another entry). After that the next step was to run a checkconfig and restart Apache.
|
||||
|
||||
Here's where it all went wrong one day. If I can recall correctly, my boss was on vacation so he had me doing a bit of extra work and launching a few more sites than I usually do. Not only that, but we also had a deadline of the end of the month which was either the next day, or the day after. I figure I'll just setup all mine for two days, and then have some extra time the next day for other things to work on. So I started launching my sites. After each one, I would add the domain it was supposed to be at into my ``/etc/hosts`` file and make sure it worked.
|
||||
Here’s where it all went wrong one day. If I can recall correctly, my boss was on vacation so he had me doing a bit of extra work and launching a few more sites than I usually do. Not only that, but we also had a deadline of the end of the month which was either the next day, or the day after. I figure I’ll just setup all mine for two days, and then have some extra time the next day for other things to work on. So I started launching my sites. After each one, I would add the domain it was supposed to be at into my /etc/hosts file and make sure it worked.
|
||||
|
||||
I was probably half way done with my sites, and suddenly I ran into one that didn't work. I checked another one to see if maybe it was just my network being stupid and not liking my hosts file, but no, that wasn't the problem. Suddenly, EVERY SITE stopped working on this server. Panicking, I delete the symlink in sites-enabled and restart Apache. Everything works again. I then proceed to put that site aside, maybe something in the php files breaks the server, who knows, but I have other sites I can launch.
|
||||
I was probably half way done with my sites, and suddenly I ran into one that didn’t work. I checked another one to see if maybe it was just my network being stupid and not liking my hosts file, but no, that wasn’t the problem. Suddenly, EVERY SITE stopped working on this server. Panicking, I delete the symlink in sites-enabled and restart Apache. Everything works again. I then proceed to put that site aside, maybe something in the php files breaks the server, who knows, but I have other sites I can launch.
|
||||
|
||||
I setup the next site and the same thing happens again, no sites work. Okay, now it's time to freak out and call our sysadmin. He didn't answer his phone, so I call my boss JB. I tell him the problem and he says he will reach out to the sysadmin and see what the problem is, all the while I'm telling JB "It's not broken broken, it just doesn't work, it's not my fault" etc etc. A couple hours later, our sysadmin emails us back and says he was able to fix the problem.
|
||||
I setup the next site and the same thing happens again, no sites work. Okay, now it’s time to freak out and call our sysadmin. He didn’t answer his phone, so I call my boss JB. I tell him the problem and he says he will reach out to the sysadmin and see what the problem is, all the while I’m telling JB “It’s not broken broken, it just doesn’t work, it’s not my fault” etc etc. A couple hours later, our sysadmin emails us back and says he was able to fix the problem.
|
||||
|
||||
It turns out, there's a hard limit to the number of files your system can have open per user, and this was set to 1000 for the www-data user. The site I launched was coincidentally the 500th site on that server, each of them having an access.log and an error.log. These two files apparently constantly open on each site for apache to log to. He was able to change www-data's ulimit to a lot higher, (I don't recall now what it was) and that gave a lot more leeway in how many sites the sites server could host.
|
||||
It turns out, there’s a hard limit to the number of files your system can have open per user, and this was set to 1000 for the www-data user. The site I launched was coincidentally the 500th site on that server, each of them having an access.log and an error.log. These two files apparently constantly open on each site for apache to log to. He was able to change www-data’s ulimit to a lot higher, (I don’t recall now what it was) and that gave a lot more leeway in how many sites the sites server could host.
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
May 26, 2021 - First flight as a PPL
|
||||
####################################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
On April 26th, I took my first flight as a Private Pilot. I was flying with a CFI for a checkout to rent planes from the Wings of Carolina club, so the flight was nothing really to talk much about. It was really hot, and my first flight in almost 5 months, so I was definitely rusty.
|
||||
|
||||
Mostly using this flight as a stepping stone to try out the GPX viewer§. I flew a PA28-161 - Warrior II - N8080A for One hour. Flew from KTTA, up north west a bit, did a few steep turns, then back to KTTA.
|
||||
|
||||
§ - Not ported over, no JS on this blog.
|
|
@ -1,37 +0,0 @@
|
|||
May 27, 2021 - Second flight as a PPL
|
||||
#####################################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
I was able to sneak in a cooler morning flight in N8080A. I took my motorcycle to the airport, but forgot my yoke mount so I was iPad-less. We had to wait for a long while to get fuel because the services truck was filling the HU-16 that had arrived a few days beforehand. There was also a C-27 taking off, super cute, Feels like a baby C-130!
|
||||
|
||||
.. figure:: {static}/images/2021/05/20210527_hu16.jpg
|
||||
:alt: Grumman HU-16 Albatross
|
||||
|
||||
Grumman HU-16 Albatross
|
||||
|
||||
.. figure:: {static}/images/2021/05/20210527_c27.jpg
|
||||
:alt: Alenia C-27J Spartan
|
||||
|
||||
Alenia C-27J Spartan
|
||||
|
||||
We went up, took a few minutes to do another 45° bank turn. I did that a little better, less shaky. Then he had me practice some emergency descents. I didn't do as well at those as I should. I need faster ADM skills. That will come with time, one of my big weaknesses is emergency things, so it's one thing I'm excited to start practicing.
|
||||
|
||||
After the emergency procedures, he had me practice rudder control. Putting in enough rudder while turning to hold on target before the turn and rolling out while pointing at a target - but rolling out. I'm much better at rolling out than rolling in, so I'm excited to have a new procedure to practice. One of the things I like a lot about this CFI giving me the checkout to borrow planes, is that he's young. He doesn't have these really old ways of thinking about things and I appreciate that.
|
||||
|
||||
After the higher altitude stuff, he wanted to see some short-field landings. The first time in the pattern we had to extend our downwind A LOT, there were three people on long finals, so our downwind was funky and long. I'm still getting used to this plane and the runway so by the time we were about to touch down, the other plane in front of us was still on the runway (albeit turning onto taxiway A3 a mile down the runway) so he said go around, as technically the other plane was still on the runway and things could go wrong even with that far separation.
|
||||
|
||||
Did a go around and the next two short fields were okay. We got off at Taxiway A2 I think, and then took taxiway A back to the ramp. When we got to the intersection with A and A1 there was another plane getting ready to cross the threshold, but it was a Cessna 172… high wing! They didn't notice that there was a taildragger apparently norad coming on a 45° final, not straight in and almost rolled into the runway. Luckily the CFI I was with shouted STOP on the CTAF and they stopped, seconds before an incursion! EEEEK!
|
||||
|
||||
Wrapped up, and planned our third checkout ride, it'll be down to KFAY, a controlled field. Should be on June 2nd and then I'll be cleared to rent the planes and feel like a full member of the Wings of Carolina!
|
||||
|
||||
Unfortunately no GPX file, but I have a screenshot.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/05/20210527_track.png
|
||||
:alt: GPX Track across the Raleigh Durham area west of Jordan Lake
|
||||
|
||||
GPX Track across the Raleigh Durham area west of Jordan Lake
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
WOC Final Checkout Ride
|
||||
#######################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
I can finally rent planes through Wings of Carolina! Flew today and the CFI passed me.
|
||||
|
||||
I was a bit nervous about the North Carolina weather so I text the instructor to see if we could leave an hour early for the controlled airspace portion of the checkout. He said let's shoot for 3:30, we took off at 4 because he gave me a bit of ground instruction on the systems in N8116J. (Also we couldn't figure out the radio, so had to push a few buttons to get comms working. It seems when 16J was in the shop, they had undone all the COM1 COM2 selection buttons, which caught us off guard.)
|
||||
|
||||
We took off, then flew south to Fayetteville (KFAY), Luke showed me the auto pilot, how to climb, descend, turn to a heading, so we enabled that on the flight to KFAY. 20 miles north, called approach, I fumbled my radio A LOT. I definitely need more controlled airspace practice. ATC Talks FAST. It's hard to fly the plane and copy things down, I think I need to start using a pen and paper, not Foreflight for ATC remarks, it'll be much easier. I put a FieldNotes book in my flight bag the other day, time to use it! After a few more fumbles (I copied back the altimeter, not the altitude, talk about stress!) I was cleared to land. Squawked 0210 and landed on runway 22 almost straight in, I took a right handed base, it was weird! There were no commercial flights so they were at a lull of traffic which is why I just got the RWY22 CLEAR TO LAND. Unfortunately (or Fortunately..) LIVE ATC and KFAY approach are down so I have no recording of my fumbles. Would have been nice to hear them again so I could learn.
|
||||
|
||||
We landed, taxied back to runway 22, and then said we were taking off VFR. Squawked 0212 now and departed, stayed runway heading until they said turn right heading 320 staying at or below 2500. Then a bit later they said fly flight plan heading I turned 355 and then we finally got out of their airspace. There's two airports there, KFAY and Simmons Army Airfield (KFBG), so their airspace looks like a cell dividing, two round circles and of course we bisected it the long way.
|
||||
|
||||
Out of their airspace Luke said "I have the controls", then banked hard 60 degrees right, and pointed down. He said "If you're ever VFR and inadvertently hit IMC weather, and get into an unusual attitude, hit this button [LVL] and presto, the wings will level." which of course they did. Auto pilot is still wild to me, I never flew with it in N43337, so it's going to take a lot to get used to, but I'm sure I'll start loving it.
|
||||
|
||||
We then called 10mi on the 45 for RWY22, did a touch and go, (I came in a little higher than I wanted I still need to learn the sight pictures for this airport, but oof it's FLAT still.) took off did the pattern once more and did a full stop.
|
||||
|
||||
On this flight, I learned the GPS a little bit more, the touch screen menu will make selecting comms so much easier, glad they have these consistently in all their planes. I also learned AutoPilot, I need to find a flight sim model with this auto pilot (I did get a Logitech/Saitek Multi Panel with AutoPilot on it this weekend, so good timing!) that I can learn how the IAS, ALT, VS, HDG buttons work better. HDG and ALT I get, those just hold heading and alt, but airspeed and vertical speed climbs are still magical!
|
||||
|
||||
Luke then signed me off, so I'm clear to rent any of the PA-28-161 that they have at Wings of Carolina. I told him I want to learn how to fly the Mooney M20J soon, I'm excited to get my complex endorsement.
|
|
@ -1,69 +0,0 @@
|
|||
First Flight With Lauren
|
||||
########################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
Today was my first flight with my wife, Lauren. She is my first real passenger ("technically your DPE is, blah blah"). I didn't know what to expect, I knew she had been up in planes before - she's gone skydiving, something I will probably never do. I'd rather be the person to fly the "JUMPERS AWAY OVER X" than be a jumper. I don't want to make this entire blog about Lauren, although we all know I could. So I will try to keep it 50% airplane talk!
|
||||
|
||||
We scheduled a 12pm flight, with an estimate of me probably taking off at 12:30 (took off at 12:40 for pattern and 12:49 to KDAN), Cross country from KTTA to KDAN and back to KTTA. I wanted to fly at 4500'msl there, and 5500'msl back, following the East is Odd +500 and West is Even +500, because it was a 358°ish flight there and a 178°ish back (that's from airport center to airport center, but I did some cloud avoidance, a few times (like, the whole time) so I was pretty off course, but ForeFlight will get me there. I brought my Stratux because I remembered that N8116J didn't like bluetooth and ADSB so my iPad wouldn't connect to the plane. I also bought a new GPYes unit that I wanted to try out, and it worked great, no more magnetic GPS sticking to random magnetic things, everything is self contained in my Stratux!
|
||||
|
||||
Wind was good for RWY21, so I had to taxi via Taxiway Alfa to get there, still not a fan of how Wings of Carolina has us do a runup off the taxiway, something I need to get used to at a busier airport than KEEN. Well, we took off and I did a loop of the pattern - I wanted to gauge Lauren's stomach, and my flying abilities to make sure she was okay to fly. The Pressure Density was 2,800'-2,900, which for a 255'msl runway, oooof. After the second takeoff we flew out to the traffic pattern then departed to the north! We climbed up to 3000, the cloud layer was about 3800 so I chose to stay under it, vs fly over the top and chance not having an opening. It was pretty bumpy - there's a convective SIGMET over like the whole east coast - so I knew it was going to be a little bumpy. Lauren was taking pictures the whole time (she took 47! I'll share some) and got some fun ones of me. In my pictures I look like I'm super concentration face, but she got a couple of me smiling.
|
||||
|
||||
Nearing KDAN I realized that the CTAF was Actually a CTAF (Common Traffic Advisory Frequency) and that KDAN had a tiny little tower. I called 15 to the south (because I heard a lot of traffic) and the nice person on the frequency came in and said something like 16J there's two planes on the taxiway, one in the pattern and one just departing, which now I understand why people come on our Unicom back at KEEN and keep saying "KEEN Unicom please advise". Well we got closer I said I was flying over midfield to make a tear drop into the downwind. I did as such, flew over at 2500', did the tear drop, down to 1500' and landed. We then taxied to the FBO and shut down [my outside camera picked THREE seconds after I shut down to die, perfect timing]. The nice ramp assistant gave us a ride to the FBO in the golf cart so we could pee.
|
||||
|
||||
Gatorade passed through our system completely we headed out to the plane. We got some weird looks from the people chilling in the FBO (Enterprise people, and like a grandfather? idk) for wearing masks. Yes we're both vaccinated, but I sure as hell don't know if the random people I run into are, gotta keep you safe!
|
||||
|
||||
We took a few pictures, and then went and started up the plane. When I was doing my run up, I didn't have the mixture full rich, was still leaned for ground ops, so when I did the mag drop I heard a backfire, was like OH SHIT and realized I was leaned. Put in full mixture, and did the mag drops again, ~150rpm loss and we were good to go. Lesson learned here is even if there are shortcuts for when the engine is hot, and you just land for 10 minutes, probably good to go through the full checklist even just skimming it.
|
||||
|
||||
We took down taxiway Alfa again and got to RWY02. Side note, KEEN has 02-20 and 14-32, this airport KDAN has 02-20 and 13-31 so when I came upon it, I was like "holycrap I feel like I'm home". Anyway - when we got to the end of the taxiway there were two entrances only like 100ft apart to the runway, it was weird. We had to wait like 10 minutes to take off, because there were 4 planes doing touch and goes and they were perfectly spaced to give me like NO time to take off. I know how long of a runway I need to be safe, but with a 2900' Density Altitude, I know I needed a longer ground roll, so finding time to slip in to where I knew I could take off was annoying. Finally one of the guys on downwind said "Plane waiting at 02, I'm extending my downwind a little bit to give you some time to take off, so I rolled out, thanked him and took off to the north a bit. I extended my upwind and gave the pattern a large buffer, then took off to the south.
|
||||
|
||||
Lauren seemed to be getting tired by like 75% of the trip back so maybe next time I'll take the plane for four hours, and then we can take a full hour between legs, instead of 15 minutes. I did three hours, because I planned for a longer break between - we even bought zucchini bread I made last night! - but I threw in that extra pattern lap before we left the airport, so that added like 15 minutes, and I couldn't find the flight book so that took some extra time.
|
||||
|
||||
When we were on the way back to Raleigh Exec, we saw another plane like 500' below us so I flew above them and circled past them then tried to come in behind them but I have no idea where they went when I flew over them, my ADSB decided to not pick them up, so I did a larger right turn so I knew I'd avoid them. It was weird and I'll have to check FlightRadar24 playback to see - but it's not up now for some reason. After that steep turn I entered the downwind and landed. We landed with 2 minutes to spare, but it took a few minutes to shut down, and tie down. Glad someone wasn't right after us (if someone was I would not have gone as far of course). Covered the plane, paid the $260 for 2.3 hours of flying, put the book away and headed home.
|
||||
|
||||
The return trip took about exactly the same length. We left KTTA at 12:49, landed at KDAN at 1:36 (49min). Then with waiting for takeoff, we left KDAN at 2:07 and landed at 2:57(50min). On the flight back, it was a bit bumpier, the clouds were still scattered at about 3800 but some were darker than others so I flew around them. I wonder if when I finally fly IFR if I'll fly a lot straighter, instead of just "oops avoid that cloud!" that remains to be seen.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_tyrel-passenger-seat.jpg
|
||||
:alt: Tyrel sitting in passenger seat, waiting for Lauren to get into plane.
|
||||
|
||||
Tyrel sitting in passenger seat, waiting for Lauren to get into plane.
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_powerlines.jpg
|
||||
:alt: Power line swath through the trees, with a nuclear power plant in the disance.
|
||||
|
||||
Power line swath through the trees, with a nuclear power plant in the disance.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_tyrel-looking-left.jpg
|
||||
:alt: Tyrel looking to the left, watching for traffic
|
||||
|
||||
Tyrel looking to the left, watching for traffic
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_danville-VA.jpg
|
||||
:alt: Danville, Virginia airport, from above.
|
||||
|
||||
Danville, Virginia airport, from above.
|
||||
|
||||
.. figure:: {static}/images/2021/06/14-clouds.jpg
|
||||
:alt: Clouds and the right wing of a Piper Warrior airplane
|
||||
|
||||
Clouds and the right wing of a Piper Warrior airplane
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_tyrel-pulling.jpg
|
||||
:alt: Tyrel pulling the plane forward, to get it lined up to push back for parking.
|
||||
|
||||
Tyrel pulling the plane forward, to get it lined up to push back for parking.
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_TTA.gif
|
||||
:alt: TTA Airpot Diagram
|
||||
|
||||
Airport Diagram of TTA
|
||||
|
||||
.. figure:: {static}/images/2021/06/14_DAN.gif
|
||||
:alt: DAN Airport Diagram
|
||||
|
||||
Airport Diagram of DAN
|
|
@ -1,52 +0,0 @@
|
|||
First Flight With My Dad
|
||||
########################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
I actually did a flight on July 7th, but It was only one lap around the pattern. It was 95°F here, and I knew I wouldn't be in the right mind to continue my flight as I got to the traffic pattern after take off, so I just called crosswind, and headed back to land, a whopping 0.3 hour flight time! So that's what just one melting traffic pattern loop looks like!
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_loop.png
|
||||
:alt: GPS track around the TTA Airport, just one pattern loop
|
||||
|
||||
GPS track around the TTA Airport, just one pattern loop
|
||||
|
||||
Anyway! My father was excited to fly with me, we took N2114F up. We intended to go from KTTA-SDZ-KRCZ, but it was still hot, so we decided to just do SDZ and back.
|
||||
|
||||
We take off, and do one lap around the pattern - I want this to be my standard when I bring new people up, it gives them a way out to say "GET ME OFF PLEASE". After that one pattern lap we headed towards SDZ. It was a really smooth flight, we flew at 4500 feet to the VOR, then tried to get to 7500 feet on the way back (We had time, I wanted to climb) but it was just SO HOT that we ended up just staying at 5500feet, the climb was taking forever!
|
||||
|
||||
When we were 10mi from the airport, it started getting super busy (BBQ day at the airport!), so we decided to waste some time in the practice area and I did a steep turn for him to waste more time. After that the traffic died down so we headed back to KTTA. I did a touch and go, a regular landing, and then being that there was no other traffic, practiced an emergency engine out procedure (what I failed on my checkride) and that went smoothly.
|
||||
|
||||
So nothing super special about this trip, besides it was my first time flying my father.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_tyrel-in-passenger-seat.jpg
|
||||
:alt: Me in the passenger seat climbing in and getting ready to go.
|
||||
|
||||
Me in the passenger seat climbing in and getting ready to go.
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_tyrel-and-tony.jpg
|
||||
:alt: Me and Dad sitting in airplane, somewhere above North Carolina
|
||||
|
||||
Me and Dad sitting in airplane, somewhere above North Carolina
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_tyrel-pointing-out-window.jpg
|
||||
:alt: Me pointing out the tiny window on the airplane.
|
||||
|
||||
Me pointing out the tiny window on the airplane.
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_propeller-and-dashboard.jpg
|
||||
:alt: Part of the dashboard, and CO detector, plus a blurry propeller in the background
|
||||
|
||||
Part of the dashboard, and CO detector, plus a blurry propeller in the background
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_right-side-haze.jpg
|
||||
:alt: Looking out the right window, the sky is hazy, part of a wing can be seen
|
||||
|
||||
Looking out the right window, the sky is hazy, part of a wing can be seen
|
||||
|
||||
.. figure:: {static}/images/2021/07/10_tony-and-tyrel.jpg
|
||||
:alt: Inside the cockpit, profile view of me, and part of my father's head.
|
||||
|
||||
Inside the cockpit, profile view of me, and part of my father's head.
|
|
@ -1,22 +0,0 @@
|
|||
Mooney M20J checkout... Sort of
|
||||
###############################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
Tuesday night I emailed my instructor saying "Hey the Mooney is available Sunday afternoon, could we start getting me ready for a checkout", and he said "sure, book it", so I did. Then last night I started reading through the POH. There's a lot of neat differences. Cowl flaps, retractable landing gear, constant speed prop. I definitely wanted to start getting my complex rating. I read through that POH, and look up a lot of videos on how to work the prop. I'm used to just throttle and mixture in the Warriors, but this has throttle, manifold pressure, and mixture levers. I learned the cool parts about how the oil pressure, and springs set the propeller angle.
|
||||
|
||||
So I get to the airport at about 1pm, and we start talking about what I know. I explained how the undercarriage stuff works, under 132kias for lowering, and under 107kias for raising, and learned from Luke that there's two different speeds because of gravity and fighting gravity. We spend the first hour talking about why you need different manifold pressures. Then we head out to the plane and do a very comprehensive pre-check. I learned that the M20J doesn't have a trim tab, the whole tail raises and lowers on a pivot, NEAT! The flaps are suuuper wide and the ailerons are kind of thin. The landing gear was an interesting inspection because of how the poles and hinges open/close the gear.
|
||||
|
||||
After the pre-flight we get flying. Things are pretty similar on the ground, as the propeller lever is pushed all the way forward, and the throttle is the main control. Luke points out that the propeller is rounded, so there's an RPM range that you shouldn't idle in, (1550-1950ish), vs the squarer prop that the other Mooney had.
|
||||
|
||||
We take off, and one thing I check different is if I have available runway left, and when I don't, I can raise the landing gear at that point. It was pretty cloudy, so we had to climb up to 5500′, and eventually we hit 7000′ to jump over some clouds. First time really being above clouds this much, for the first hour we were over them. For the climb out he told me to set the plane to "twenty-five squared" - 2500rpm and 25in/hg. And every so often I would need to add more manifold pressure because of the atmosphere lapse rate while climbing.
|
||||
|
||||
We got up to 6000′ ish, initially and then did some straight and level flying, super smooth above the clouds today. Then we did some 30 degree turns, did a few of those okay. When we did 45 degree turns, my first left one was kind of bad - lost a lot of altitude. One to the right was okay, and then the third one to the left I kept my altitude right.
|
||||
|
||||
After turns we did slow flight, and it's pretty much the same controls. The power off stalls I was I guess putting in unconscious left aileron, because we kept starting to spin a little to the left, next time I fly I definitely need to practice that more.
|
||||
|
||||
Well we ended up going pretty far east, at one point we were like 15 miles southeast of RDU, felt uncomfortable not talking to anyone there, but I guess it was out of the normal flight path for the jets so we were fine.We ended up needing to head back to the airport for 4pm, so I put the plane in a 750fpm descent while heading back, at one point I was able to punch through the clouds at around 2500′, and we joined the traffic pattern on the 45 for downwind on 21. I landed VERY well he said. He said that people transitioning from Warriors to Mooneys land hard because the M20J is a lot lower of a plane than the PA28, so they flare early and land hard. I didn't flare early both times we landed so he said we could just end for the day. I always love when instructors say I do well with landings!
|
||||
|
||||
We then get back to the airport to do some payments and find out "Oh, Tyrel needs 250 hours without an instrument rating, to fly the M20J, or 150 with an instrument rating." So Oops, I guess it'll be a while before I can rent this, and get an actual check out.
|
|
@ -1,50 +0,0 @@
|
|||
Cessna 152 Checkout
|
||||
###################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
Today I got checked out in a Cessna 152. It was really my first time (besides spin training) flying high wing planes and I was a little nervous. We had a pretty standard pre-flight check, took a lot longer than just a "I'm out here to go on a flight", again because Luke was explaining things to me. There's a lot of differences like with the warrior, all the flaps are on hinges, but in the Cessna, there's one pulley hinge and some rollers you need to check, not just actuation hinges. Pointed out how the landing gear is different, there's plastic fairings that we need to repair quite frequently, and there are no dampeners.
|
||||
|
||||
After the pre-flight we took off, Vr is pretty low, at 50 so the plane just wanted to float almost immediately in my opinion. It was also a cooler day outside than my most recent few flights, so that helped too. We took off, headed north to the practice area. I get up to 3000' msl and we level off, trim for cruise flight and lean the engine. This plane also has a vernier mixture control, so it's nice to be able to dial in the mixture, even if there's no on screen display of the gallons per hour like the M20J. There were some clouds at 4000' I think, but they were tiny, and we figured we didn't need to go above them, so we stuck at the 3000' level.
|
||||
|
||||
This is where Luke says to just take the plane and do tiny things with it, like turn it uncoordinated, see how much rudder I'd need to do a turn. So I did that for a bit, did a standard rate turn to the left, and we switched to some 30° turns, leveled off then did two 45° turns, back to back. I hit my prop wash at the end of the second one, that always feels great. The first few turns were gross, this plane has old cables for the ailerons, so there's a lot of play when turning, so it took a few tries to be able to maintain altitude and find that comfortable dead spot with cable tension. The last plane (M20J) I flew, everything was much stiffer for turning.
|
||||
|
||||
After the few turns, he said "oh no, there goes your engine" and throttled to idle. I looked around for a place to land, and didn't see one immediately. One thing I could have done better is look out the back window, because the 152 actually has one! Well I found a spot to "crash land" so I brought the plane to Vglide (60) and slowly descended towards the place to land. I guess in my "everything is okay" did the A B part of the emergency checklist, but I didn't do ABCDE, so we did it again. This time I:
|
||||
|
||||
* A- pitched for best airspeed (60kts)
|
||||
* B- found the best place to land
|
||||
* C - Checklist, pretended to check fuel, master, key, primer, etc.
|
||||
* D - pretended to switch to 121.5mHz and declare an emergency
|
||||
* E- executed the landing, and prepared to exit (opened the door, turn off mixture, etc so the plane doesn't blow up and I can get out)
|
||||
|
||||
and found a cute little field to land in. That was successful so we headed back towards the airport.
|
||||
|
||||
At the airport everything was standard traffic pattern. There were three of us in the pattern, one tail dragger that was always just behind us, really friendly guy who liked chatting on frequency, and one low wing - maybe a warrior? - I can't remember. Well I did six landings. One normal landing, three short field (the last one I did great, landed on numbers and was done before A2 taxiway entrance) and then a few more normal.
|
||||
Luke said that I was death gripping the yoke, so he did one lap around the airport - where he trimmed and only used his two fingers lightly to move the yoke. Watching him do that, I copied and did a lap around the pattern the same, much easier this time.
|
||||
|
||||
We then landed, taxied back and went to park. Parking is WILD, you sit on the tail and then back then walk backwards to get the plane in place. I guess when your plane's max ramp weight is 1675lbs, that's easy to do! Three times as much as my motorcycle… After we chatted, he said he feels safe with me flying it, and I agreed. "I feel safe, but not super comfortable, but that only comes with time so I feel safe to take it up and get more comfortable".
|
||||
|
||||
I then had to fill out the quiz, and scanned it, then emailed it to him.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/08/04_me-being-weird.jpg
|
||||
:alt: Picture of me in the cockpit being a weirdo with a big smirky mouth
|
||||
|
||||
Picture of me in the cockpit being a weirdo with a big smirky mouth
|
||||
|
||||
.. figure:: {static}/images/2021/08/04_cessna-152-cockpit.jpg
|
||||
:alt: The cockpit of a Cessna 152, yokes, gauges, etc. Outside you can see other planes on the ramp.
|
||||
|
||||
The cockpit of a Cessna 152, yokes, gauges, etc. Outside you can see other planes on the ramp.
|
||||
|
||||
.. figure:: {static}/images/2021/08/04_3d-track-1.jpg
|
||||
:alt: Just a 3d diagram of the flight, not sure what I was focusing on here.
|
||||
|
||||
Just a 3d diagram of the flight, not sure what I was focusing on here.
|
||||
|
||||
.. figure:: {static}/images/2021/08/04_3d-track-2.jpg
|
||||
:alt: Just a 3d diagram of the flight, not sure what I was focusing on here.
|
||||
|
||||
Just a 3d diagram of the flight, not sure what I was focusing on here.
|
|
@ -1,57 +0,0 @@
|
|||
Two flights and some nice weather
|
||||
#################################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
The other day there was a call to action on the Wings of Carolina slack. "Is anyone able to help this pilot get one of our planes back?" Seems this newly licensed pilot, (Congrats!) passed his check ride on Friday and the weather was not great so had to leave N69012 at Asheboro. I said I would be glad to help out if the IFR weather cleared by 9am, I could give him a ride over in N8080A.
|
||||
|
||||
I booked a 9am-12pm block, and got to the airport at 8:55am. Grabbed the 80A book book and went to the lounge to check weather. Luckily the fog had burned off and the skies were clear! The pilot met me in the lounge, I wrapped up the weather briefing (nothing of note) and we went out to preflight. The left red nav light was out, but that's only required at night, confirmed by asking the other pilot. The fuel truck came and filled us up to the tabs (34 gallons) and we were off.
|
||||
|
||||
My flight plans were from KTTA -> KHBI (drop off pilot) -> KEXX then back to KTTA. Just under a 2 hour round trip, which took a bit longer because when we got to the hold short line for RWY03, I realized my iPad wasn't connected to the GPS, so we fiddled with it for a few (no one was behind us, but oof Hobbs running) and couldn't get it working. That's fine, we had our GPS and the pilot knew what KHBI looked like form the air. We took off, departed the pattern to the north, got to a little bit higher then turned west.
|
||||
|
||||
The pilot was super helpful, having a copilot be able to put in the radios for Siler City as we passed, and the AWOS/CTAFs in for KHBI was actually a really big load off my plate. It's the little things! Flew at about 3000ft over to KHBI because It was only a 20 minute flight so I stayed low. We get to the airport and he lets me know that RWY24 has a papi, so we chose that runway to land on. Land pretty okay, didn't grease it, but it is what it is. Taxi over and get him to his plane. I shut down so he can get out safely, then realize after he got out, I CAN'T OPEN THE DOOR. I had to yell him over to make sure I could open the door again, the bottom latch was stuck! I recorded a video, then instagrammed a `fellow pilot who is famous in his circles for getting stuck in his plane and having to call someone down in the area who landed and helped him out <https://www.instagram.com/p/CLnMONphlsu/>`_. Told him he's not alone, hah.
|
||||
|
||||
Anyway, I was able to open the door so I felt like it was okay if I crashed and had to open the door myself. I turn the plane back on, plug in my Stratux for ADSB on iPad, and get ready to take off. I taxi over to the runway (took 24 again out) and hold short for a taildragger and another plane to land. I then take off and woahh there were like 80 birds at the end of the runway at like 300ft up. Luckily I was able to scare them and flew above them, then departed to the right (west) and headed to KEXX. Luckily thr CTAF is the same for both (122.8) so I was able to hear the traffic without fiddling with the radio. I set the AWOS beforehand, so I checked that when I was close, and still winds calm, not bad.
|
||||
|
||||
Got 10 miles, out, announced position, 5 miles out, announced I was entering the downwind at a 45. I was on the down when a pilot to my right asked if I was on base, kind of weirded out because I wasn't so I was vigilant and said I was on downwind (again…). Then called base, and final and landed. Final was neat at Davidson county, had to fly over a factory, which was kind of cool.
|
||||
|
||||
Landed, taxied back to the runway and lined up and waited again. The taildragger had followed me! Saw him land as I was at the hold short line. Waited for a jet to land and then off I went! I climbed out, departed to the east, and climbed up to 5500msl. Held 5500 very well this trip, the air was super calm and I'm getting better at electric trim, much easier than just wheel trim.
|
||||
|
||||
At one point I turn the auto pilot on, with it set to 109° and 5500msl, but for some reason it made me descend and banked me left 45° and I wasn't liking that so I disengaged it. I climbed up back to 5500' for the rest of my trip. By the time I was back to KTTA, the winds still favored RWY03, so I joined the pattern on a 45° entry, and landed smoothly. At around 3000msl descending near Ashbury it was a bit bumpy, but that's the only turbulence I experienced. Such a nice morning.
|
||||
|
||||
Well I get back to the airport and land and shut down… I'm stuck again! Door won't open. There was no one around I could yell to, so I called the front desk, no answer. I tried again, using different pressures and trying to see if there was like a little latch that didn't hook. I fiddled for a few minutes and was able to get out, I guess I got it just right.
|
||||
|
||||
I then cover the plane, and squawk the door not opening, and posted the video on slack. The next pilot replied to my slack post later that evening that he had no problems. Maybe I'm just door cursed.
|
||||
|
||||
Lauren and I then went to lunch before my next flight where I was taking her up in a Cessna 152 (N89333). Well we do the preflight dance, go taxi and take off. At like 300' above the runway, the damn pilot side door opens up! It's fine but I don't want to worry my wife, on her second flight with me ever, so I have her hold the door closed while I go finish the pattern loop (I was doing that anyway). Well MORE fun happened the pilots PTT(push to talk) button got stuck off, so I had to use her microphone to talk, (I could have just switched the plugs, but we were in the base turn). I kind of overshot base so had to over correct a little bit, but we landed okay, taxied back and agreed we were discontinuing our flight. We could have gone back up and carried on - we had the allotted time - but you know what? The rest of the flight wasn't in the cards.
|
||||
|
||||
Video of me trapped in The Warrior - `https://youtu.be/0uAL30nCuYE <https://youtu.be/0uAL30nCuYE>`_.
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/08/08_cockpit_selfie.jpg
|
||||
:alt: Selfie in the cockpit, me wearing a blue shirt.
|
||||
|
||||
Cockpit Selfie
|
||||
|
||||
.. figure:: {static}/images/2021/08/08_behind_left_wing.jpg
|
||||
:alt: A look at the ground behind the left wing
|
||||
|
||||
A look at the ground behind the left wing
|
||||
|
||||
.. figure:: {static}/images/2021/08/08_behind_right_wing.jpg
|
||||
:alt: Looking at a runway in the distance, not sure which one now.
|
||||
|
||||
Looking at a runway in the distance, not sure which one now.
|
||||
|
||||
.. figure:: {static}/images/2021/08/08_hazy-highway.jpg
|
||||
:alt: Looking in front of the left wing, at a highway, the sky is hazy
|
||||
|
||||
Looking in front of the left wing, at a highway, the sky is hazy
|
||||
|
||||
.. figure:: {static}/images/2021/08/08_hazy_runway.jpg
|
||||
:alt: Hazy sky with a runway a couple miles away.
|
||||
|
||||
Hazy sky with a runway a couple miles away.
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
Back Above Keene
|
||||
################
|
||||
:author: tyrel
|
||||
:category: flying
|
||||
:tags: flying
|
||||
:status: published
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_me_mom_n43337.jpg
|
||||
:alt: Mom and I hugging in front of the right wing of N43337
|
||||
|
||||
Mom and I hugging in front of the right wing of N43337
|
||||
|
||||
It's my brother's wedding weekend and he asked me to take him and his new father-in-law flying. On October 16th I get to the airport, very well knowing that it's still too foggy for my 8am-10am flight that I was about to cancel in person. I still went in, because I haven't seen Beth in almost a year and wanted to say hi. We caught up, talked about how I've been going to Monadnock Aviation since I was in college - after my first flight on March 17, 2010! I called Levi and told him that we weren't flying, so he should just go finish getting ready for his wedding at 11:30.
|
||||
|
||||
The next day I had booked for my mother to go up the first time with me. We get to the airport at 9:55 and the FBO is locked up, Uhhhh. I email/text some people and no one knows how to get a hold of the desk attendant. We had apparently JUST missed David, one of the CFIs, who was getting into N44836 with a student I presume. So we waited a bit and it seems he was called away to do some fueling with the fuel truck. No fault of his at all, Sundays can get a little rough with only one person being at the FBOs desk.
|
||||
|
||||
We finally grab the book and keys and I go out and preflight. I'm in N43337 today, my favorite plane. I'm even wearing my "WARRIOR 337" shirt I got for soloing, for good luck! Preflight was easy as usual, once you've done it a hundred times in the same plane, you know what you're looking for from the checklists.
|
||||
|
||||
I waved to mom and Lauren to come over and we got in, I showed mom and Lauren how to set up the headphones and get into the back seat. Following a safety briefing we were off!
|
||||
|
||||
We taxied over from the Northwest ramp (The FBO area) to the East ramp and I did my run up there, the winds were 340° at 7kts gusting to 17, so the other planes were using runway 32. Waited around a bit for a radio check, the PTT button was sticky and no one was replying to my ask for radio checks, even though there were a few planes around, oh well.
|
||||
|
||||
We took off on runway 32 after waiting in line (it was busy today, wow!) and I did a lap around the pattern. It was not clean, I haven't flown in just over two months, and we had the added weight of a back passenger, so I was a little nervous the first pattern loop. But I will always do one pattern loop with a new passenger - just to give them a chance to bail out!
|
||||
|
||||
I'm not fond of runway 32, it has a high hill over Marcy Hill in Swanzey, NH and it always throws me off (probably because I have like 300 landings on runway 02 and maybe 15 on runway 32). The landing was fine, Lauren was taking pictures from the back and my mom said it was "wicked smooth, and you barely even felt the tires hit, I thought it was great, especially with the wind and everything" which as a first time passenger in a "oh my god I didn't know it was quite this small" airplane, I feel good about!
|
||||
|
||||
We then taxied back to 32, and took off again, this time it was a west departure out to Spofford Lake and over my mom's house in Chesterfield. I probably should have headed to Brattleboro first after Spofford. Had I done this, we would have been in position to fly Brattleboro, VT north to Putney, VT west of the Connecticut River and my mom would have gotten a MUCH nicer view of her house. Instead we flew over the lake and through a little valley over Westmoreland and went south along the river.
|
||||
|
||||
At one point I saw a dark cloud above and said "Okay we're about to go under a dark cloud, I'll try to avoid it but it might get turbulent", so mom and Lauren would know to hold on and probably 10 seconds later the plane went "woomp" down a bit because of turbulence - so they were prepared. After that small cloud we found a tiny patch of clean air and I turned to the right a little bit above Exit 3 and headed north again towards moms house, staying a little bit west of the river. I paralleled I91 again for a minute or two and then we got in line that I could fly close enough to mom's house that she could see it.
|
||||
|
||||
After that fun bit we headed back, directly over Spofford Lake for some more sights, and onward to KEEN.
|
||||
|
||||
We flew over Yale Forest, and I saw a cool cliff face I had never seen before - as we were entering RWY32 on a 45° entry. Entered the pattern and found myself VERY high (900msl at at 488msl airport) on final, on a 4000' runway with a displaced threshold so I executed a go around there. I probably could have made it, but with the wind and avoiding Marcy Hill, I figure it's always safe to Go Around.
|
||||
|
||||
The next loop I had my sight pictures again at runway 32 and we landed, rolled out to Taxiway Sierra and parked the plane!
|
||||
|
||||
Mom said it was fun!
|
||||
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_back-of-my-head.jpg
|
||||
:alt: Back of my head while turning a bit
|
||||
|
||||
Back of my head while turning a bit
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_cloudy-sun-view.jpg
|
||||
:alt: Cloudy and Sunny View off the right wing. Monadnock in the distance.
|
||||
|
||||
Cloudy and Sunny View off the right wing. Monadnock in the distance.
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_hannaford-kmart.jpg
|
||||
:alt: Turning over route 9 near Home Depot and Hannaford
|
||||
|
||||
Turning over route 9 near Home Depot and Hannaford
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_landing-32-14-on-final.jpg
|
||||
:alt: Cockpit view, a mile out from runway 32/14 with the runway in sight.
|
||||
|
||||
Cockpit view, a mile out from runway 32/14 with the runway in sight.
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_landing-32-14-short-final.jpg
|
||||
:alt: Cockpit view, a 1/4 mile from runway 32/14 with the runway in sight.
|
||||
|
||||
Cockpit view, a 1/4 mile from runway 32/14 with the runway in sight.
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_left-wing-looking-at-airport-and-monadnock.jpg
|
||||
:alt: Looking off the left wing at mount Monadnock.
|
||||
|
||||
Looking off the left wing at mount Monadnock.
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_sun-above-right-wing.jpg
|
||||
:alt: Just pretty sky views, out the right window above the right wing at the sun and clouds.
|
||||
|
||||
Just pretty sky views, out the right window above the right wing at the sun and clouds.
|
||||
|
||||
.. figure:: {static}/images/2021/10/17_turning-from-backseat.jpg
|
||||
:alt: Three degree turn above moms house.
|
||||
|
||||
Three degree turn above moms house.
|
|
@ -2,8 +2,8 @@ Garage Door Opener
|
|||
##################
|
||||
:date: 2022-01-09 22:46
|
||||
:author: tyrel
|
||||
:category: Automation
|
||||
:tags: home-assistant, home, esp8266, automation, esphome
|
||||
:category: Tech
|
||||
:tags: home-assistant, home
|
||||
:slug: garage-door-opener
|
||||
:status: published
|
||||
|
||||
|
@ -26,7 +26,7 @@ I knew I would need some sort of relay (domain purchased from is gone) and `reed
|
|||
|
||||
Home Assistant has a plugin called ESPHome where you can write yaml files to configure an esp8266 module. This then builds a binary which you need to flash onto the esp8266 at least once via usb. From then on you can then on you can upload from a web form and drop the bin file in manually, or just press the UPLOAD button from ESPHome. I set my relay up on pin 19/D1 for the digital pin, and 16/GND,10/3v3 for the power. The Reed switch I tossed on 15/D7 and 11/GND but that could have been anywhere. See Schematic below. It still doesn't have an enclosure.
|
||||
|
||||
.. figure:: {static}/images/2022/01/09_relay.jpg
|
||||
.. figure:: https://thumbnails-photos.amazon.com/v1/thumbnail/ipyyo6AWROe1t6_LDvhs-w?viewBox=1742%2C1306&ownerId=A2XF3XCOUKGXAO
|
||||
:alt: Relay in blue, and wires going to the NodeMCU
|
||||
|
||||
Relay in blue, and wires going to the NodeMCU
|
||||
|
@ -56,7 +56,7 @@ I added some markers to figure out what I needed to imitate in ESPHome, and saw
|
|||
|
||||
This looks like this in yaml:
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code:: yaml
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
|
@ -78,7 +78,7 @@ I'm pretty sure I jumped and screamed with excitement when it opened!
|
|||
|
||||
Once the door was opening and closing, I was able to add more yaml to set another binary sensor to show whether it was open or closed (from the reed sensor):
|
||||
|
||||
.. code-block:: yaml
|
||||
.. code:: yaml
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
|
@ -90,22 +90,6 @@ Once the door was opening and closing, I was able to add more yaml to set anothe
|
|||
|
||||
All together this is shown on my Home Assistant Lovelace dashboard using two cards, one that shows a closed door, and one with an open door (both actual pictures of the door!) with a button to open it. Once it opens or closes the other card switches into place, Home Assistant at least at the time didn't have good conditional cards like I wanted.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
type: conditional
|
||||
conditions:
|
||||
- entity: binary_sensor.garage_door_closed
|
||||
state: 'on'
|
||||
card:
|
||||
type: picture-glance
|
||||
title: Garage (Closed)
|
||||
image: 'https://tyrel.dev/house/garage_door.jpeg'
|
||||
entities:
|
||||
- entity: switch.garage_remote
|
||||
hold_action:
|
||||
action: none
|
||||
|
||||
|
||||
.. figure:: {static}/images/2022/01/garage-Lovelace_garage_door_closed.png
|
||||
:alt: Closed door state and button
|
||||
|
||||
|
@ -113,19 +97,6 @@ All together this is shown on my Home Assistant Lovelace dashboard using two car
|
|||
|
||||
Happy with the state of my Garage Door opening button, I can now yell at my phone to open the garage door (it's a "secure" switch so it requires the phone to to be open before OK Google will trigger the door).
|
||||
|
||||
There's a couple more pictures in my `Instagram post <https://www.instagram.com/p/CIrYO3SlxON/>`__ about it.
|
||||
There's a couple more pictures in my `Instagram post <https://www.instagram.com/p/CIrYO3SlxON/>`__ about it, and another `write up on my wiki. <https://tyrel.website/wiki/Garage_Door_ESPHome>`__
|
||||
|
||||
I know I could have bought a device to do this myself, but this is fully mine, my code, and my experiment with learning how to automate things at home, I gained way more out of this project than I did if I just bought a MyQ or what ever is popular these days.
|
||||
|
||||
Bill of Materials
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
* `Magnetic Switch <https://www.amazon.com/gp/product/B00LYCUSBY/>`_
|
||||
* `NodeMCU <https://www.amazon.com/gp/product/B07HF44GBT/>`_
|
||||
* `Relay Shield <https://acrobotic.com/products/acr-00016>`_
|
||||
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
This is no longer in service, as I replaced the door and have a Chamberlain MyQ system now. Less fun, but at least it's serviceable.
|
||||
|
|
|
@ -18,23 +18,31 @@ The tool I've chosen for reading EPUBs is the Python library `ebooklib <https://
|
|||
|
||||
My first task was to find an EPUB file, so I downloaded one from my calibre server. I convert all my ebook files to ``.epub`` and ``.mobi`` on my calibre server so I can access them anywhere I can read my OPDS feed. I chose Throne of Glass (abbreviating to ``TOG.epub`` for rest of post). Loading I launched Python, and ran
|
||||
|
||||
.. code-block:: console
|
||||
.. code:: console
|
||||
|
||||
>>> from ebooklib import epub
|
||||
>>> print(book := epub.read_epub("TOG.epub")
|
||||
|
||||
This returned me a ``<ebooklib.epub.EpubBook object...>`` , seeing I had an EpubBook I ran a ``dir(book)`` and found the properties available to me
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
['add_author', 'add_item', 'add_metadata', 'add_prefix',
|
||||
'bindings', 'direction', 'get_item_with_href', 'get_item_with_id',
|
||||
'get_items', 'get_items_of_media_type', 'get_items_of_type',
|
||||
'get_metadata', 'get_template', 'guide',
|
||||
'items', 'language', 'metadata', 'namespaces', 'pages', 'prefixes',
|
||||
'reset', 'set_cover', 'set_direction', 'set_identifier', 'set_language',
|
||||
'set_template', 'set_title', 'set_unique_metadata', 'spine',
|
||||
'templates', 'title', 'toc', 'uid', 'version']
|
||||
'bindings',
|
||||
'direction',
|
||||
'get_item_with_href', 'get_item_with_id', 'get_items',
|
||||
'get_items_of_media_type', 'get_items_of_type', 'get_metadata',
|
||||
'get_template', 'guide',
|
||||
'items',
|
||||
'language',
|
||||
'metadata',
|
||||
'namespaces',
|
||||
'pages', 'prefixes',
|
||||
'reset',
|
||||
'set_cover', 'set_direction', 'set_identifier', 'set_language', 'set_template', 'set_title', 'set_unique_metadata', 'spine',
|
||||
'templates', 'title', 'toc',
|
||||
'uid',
|
||||
'version']
|
||||
|
||||
Of note, the ``get_item_with_X`` entries caught my eye, as well as ``spine``. For my file, ``book.spine`` looks like it gave me a bunch of tuples of ID and a ``"yes"`` string of which I had no Idea what was. I then noticed I had a ``toc`` property, assuming that was a Table of Contents, I printed that out and saw a bunch of ``epub.Link`` objects. This looks like something I could use.
|
||||
|
||||
|
@ -42,7 +50,7 @@ I will note, at this time I was thinking that this wasn't the direction I wanted
|
|||
|
||||
Seeing I was on at least some track, I opened up PyCharm and made a new Project. First I setup a class called Epub, made a couple of functions for setting things up and ended up with
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
class Epub:
|
||||
def __init__(self, book_path: str) -> None:
|
||||
|
@ -52,7 +60,7 @@ Seeing I was on at least some track, I opened up PyCharm and made a new Project.
|
|||
|
||||
I then setup a ``parse_chapters`` file, where I loop through the TOC. Here I went to the definition of ``Link`` and saw I was able to get a ``href`` and a ``title``, I decided my object for chapters would be a dictionary (I'll move to a DataClass later) with ``title`` and ``content``. I remembered from earlier I had a ``get_item_by_href`` so I stored the itext from the TOC's href: ``self.contents.get_item_with_href(link.href).get_content()``. This would later prove to be a bad decision when I opened "The Fold.epub" and realized that a TOC could have a tuple of ``Section`` and ``Link``, not just ``Links``. I ended up storing the item itself, and doing a double loop in the ``parse_chapters`` function to loop if it's a tuple.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
def parse_chapters(self) -> None:
|
||||
idx = 0
|
||||
|
@ -67,7 +75,7 @@ I then setup a ``parse_chapters`` file, where I loop through the TOC. Here I wen
|
|||
|
||||
``_parse_link`` simply makes that dictionary of ``title`` and ``item`` I mentioned earlier, with a new ``index`` as I introduced buttons in the DearPyGUI at this time as well.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
def _parse_link(self, idx, link) -> None:
|
||||
title = link.title
|
||||
|
@ -81,7 +89,7 @@ That's really all there is to make an MVP of an EPUB parser. You can use ``Beaut
|
|||
|
||||
In my implementation my Epub class keeps track of the currently selected chapter, so this loads from all chapters and sets the ``current_text`` variable.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
def load_view(self) -> None:
|
||||
item = self.chapters[self.current_index]['item']
|
||||
|
|
|
@ -9,7 +9,7 @@ Scrollbar Colors
|
|||
|
||||
Was talking to someone about CSS Nostalgia and "back in my day" when scrollbar colors came up.
|
||||
|
||||
.. code-block:: css
|
||||
.. code:: css
|
||||
|
||||
/* For Chromium based browsers */
|
||||
::-webkit-scrollbar {
|
||||
|
|
|
@ -17,11 +17,11 @@ My first job out of college was a Python/Django company - and that directed my n
|
|||
Django, if you are unaware, is a MVC framework that ships with a really great ORM.
|
||||
You can do about 95% of your database queries automatically by using the ORM.
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
entry, created = Entry.objects.get_or_create(headline="blah blah blah")
|
||||
|
||||
.. code-block:: python
|
||||
.. code:: python
|
||||
|
||||
q = Entry.objects.filter(headline__startswith="What")
|
||||
q = q.filter(pub_date__lte=datetime.date.today())
|
||||
|
@ -49,7 +49,7 @@ Full design disclosure: I followed a couple of blog posts in order to develop th
|
|||
In order to instantiate a model definition, it's pretty easy.
|
||||
What I did is make a new package called ``models`` and inside made a file for my Album.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
type Album struct {
|
||||
ID string `json:"id" gorm:"primary_key"`
|
||||
|
@ -67,7 +67,7 @@ Each of the controller functions were bound to a ``gin.Context`` pointer, rather
|
|||
|
||||
The ``FindAlbum`` controller was simple:
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
func FindAlbum(c *gin.Context) {
|
||||
var album models.Album
|
||||
|
@ -79,7 +79,7 @@ The ``FindAlbum`` controller was simple:
|
|||
|
||||
Which will take in a ``/:id`` path parameter, and the GORM part of this is the third line there.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
models.DB.Where("id = ?", c.Param("id")).First(&album).Error
|
||||
|
||||
|
@ -90,7 +90,7 @@ Error handling is standard Go logic, ``if err != nil`` etc and then pass that in
|
|||
|
||||
This was really easy to set up, and if you want to get a slice back you just use ``DB.Find`` instead, and bind to a slice of those structs.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
var albums []models.Album
|
||||
models.DB.Find(&albums)
|
||||
|
@ -109,7 +109,7 @@ I'll only bother describing the ``models`` package here, as thats the SQLX part
|
|||
|
||||
In the ``models/album.go`` file, there's your standard struct here, but this time its bound to ``db`` not ``json``, I didn't look too deep yet but I presume that also forces the columns to set the json name.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
type Album struct {
|
||||
ID int64 `db:"id"`
|
||||
|
@ -120,7 +120,7 @@ In the ``models/album.go`` file, there's your standard struct here, but this tim
|
|||
|
||||
An interface to make a service, and a receiver are made for applying the ``CreateAlbum`` form (in another package) which sets the form name and json name in it.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
func (a *Album) ApplyForm(form *forms.CreateAlbum) {
|
||||
a.ID = *form.ID
|
||||
|
@ -135,7 +135,7 @@ Nested inside the ``models/sql/album.go`` file and package, is all of the Receiv
|
|||
I'll just comment the smallest one, as that gets my point across.
|
||||
Here is where the main part of GORM/SQLX differ - raw SQL shows up.
|
||||
|
||||
.. code-block:: go
|
||||
.. code:: go
|
||||
|
||||
func (s *AlbumService) GetAll() (*[]models2.Album, error) {
|
||||
q := `SELECT * FROM albums;`
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
Office Meeting Sensor
|
||||
#####################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: python, nodered, home-assistant, automation
|
||||
:status: published
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
|
||||
This post is ported over from my wiki, so the format isn't as storytelling as a blog post could be, but I wanted it here.
|
||||
|
||||
Bill of Materials
|
||||
=================
|
||||
|
||||
* `Raspberry Pi Zero W H (WiFi + Headers) <https://www.adafruit.com/product/3708>`_
|
||||
* `BlinkT LED Strip GPIO <https://shop.pimoroni.com/products/blinkt>`_
|
||||
|
||||
Home Assistant Parts
|
||||
====================
|
||||
|
||||
Third Party Plugin Requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* `Node-RED <https://community.home-assistant.io/t/home-assistant-community-add-on-node-red/55023>`_
|
||||
* `HACS <https://hacs.xyz/>`_
|
||||
* `Mosquitto <https://github.com/home-assistant/addons/blob/master/mosquitto/DOCS.md>`_
|
||||
|
||||
Zoom Plugin
|
||||
~~~~~~~~~~~
|
||||
|
||||
I followed the Read Me from https://github.com/raman325/ha-zoom-automation#installation-single-account-monitoring and set up a Zoom Plugin for my account, that will detect if I am in a meeting or not.
|
||||
|
||||
Pi Zero
|
||||
~~~~~~~
|
||||
|
||||
I have a tiny project Enclosure box that I dremeled a hole for the GPIO pins in the cover and I then sandwich the Blinkt onto the Pi Zero with another dremeled hole running to the micro usb power, and that's it for hardware.
|
||||
|
||||
For software, I installed the python packages for Pimoroni and Blinkt, which came with a lovely set of sample projects. I deleted everything except the `mqtt.py <https://github.com/pimoroni/blinkt/blob/master/examples/mqtt.py>`_ file, which I then put my Mosquitto server settings.
|
||||
|
||||
I then added a new service in systemd to control the mqtt server
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
[Unit]
|
||||
Description=Meeting Indicator
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/python2 /home/pi/mqtt.py
|
||||
WorkingDirectory=/home/pi/Pimoroni/blinkt/examples
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=sysinit.target
|
||||
|
||||
|
||||
Pleased with the results, and testing by sending some messages over mqtt that changed the color, I then dove into Node-RED
|
||||
|
||||
Node-Red
|
||||
~~~~~~~~
|
||||
|
||||
This is my first project using Node-RED, so I'm sure I could optimize better, but I have two entry points, one is from running HomeAssistant app on my mac, which gets me sensor data for my webcam, and the other is the aforementioned Zoom Presence plugin I created. These are ``Events:State`` nodes.
|
||||
|
||||
When either of these are True, they call first my ceiling light to turn on, which next will then add a ``msg.payload`` of
|
||||
|
||||
.. code::
|
||||
|
||||
rgb,0,255,0,0
|
||||
rgb,1,255,0,0
|
||||
rgb,2,255,0,0
|
||||
rgb,3,255,0,0
|
||||
rgb,4,255,0,0
|
||||
rgb,5,255,0,0
|
||||
rgb,6,255,0,0
|
||||
rgb,7,255,0,0
|
||||
|
||||
as one string. This leads to a Split, which will in turn, emit a new MQTT message for each line (I split on ``\n``) and turn on all 8 LEDs as red. This is inefficient because I am still using the sample code for the blinkt which requires you to address each LED individually, my next phase I will remove the pin requirement and just have it send a color for all of them at once, one line.
|
||||
|
||||
When either of the sensors states are False, I then flow into a Time Range node, in which I check if it's between 9-5 or not. If it is, then I turn all the LEDs Green, and if it's outside 9-5 I just turn the LEDs off. I do not turn OFF the overhead light, in case it was already on. I don't care about the state enough.
|
||||
|
||||
I also intentionally trigger at the Office Hours node, which will inherently turn the Green on at 9:01am, and off at 5:01pm. As well as turn on Red for any long standing meeting times I have.
|
||||
|
||||
Images
|
||||
~~~~~~
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_nodered.png
|
||||
:alt: Screenshot of Nodered, with the flow of control for turning on the lights.
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_lights.jpg
|
||||
:alt: wall mounted enclosure with a strip of LED lights.
|
||||
|
||||
Videos
|
||||
~~~~~~
|
||||
|
||||
* https://i.imgur.com/kKIafiI.mp4
|
||||
* https://i.imgur.com/DLypDGD.mp4
|
||||
|
||||
Source
|
||||
~~~~~~
|
||||
|
||||
Nodered configuration source json https://gist.github.com/tyrelsouza/c94329280848f0319d380cc750e995c2
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
Coffee Gear
|
||||
###########
|
||||
:author: tyrel
|
||||
:category: Coffee
|
||||
:tags: coffee gear, coffee beans, coffee
|
||||
:status: published
|
||||
|
||||
|
||||
I put this up on my wiki a bit ago when a friend asked for coffee recommendations. Hopefully you can enjoy it and learn about some coffee machines you don't know yet.
|
||||
|
||||
|
||||
************
|
||||
What I drink
|
||||
************
|
||||
|
||||
Woke Living Coffee
|
||||
==================
|
||||
|
||||
My favorite coffee is from Pamela and Marcus at https://wokelivingcoffee.com/. They are a couple of local to me roasters in Wake Forest, NC who have connections to a farm in La Dalia, Nicaragua. Not only do they sell great coffee, they are extremely nice and we visit them any chance we get at our local `Black Farmers Market <https://blackfarmersmkt.com/>`_.
|
||||
|
||||
****
|
||||
Gear
|
||||
****
|
||||
|
||||
Grinders
|
||||
========
|
||||
|
||||
I prefer burr grinders, there's documented evidence that they are better, I won't get into that here.
|
||||
|
||||
Baratza
|
||||
=======
|
||||
|
||||
I use a `Baratza Virtuoso <https://baratza.com/grinder/virtuoso/>`_ that I picked up refurbished. It works great! For drip coffee I will grind at step 28, for aeropress I will grind at 20, and for french press I will set to 30.
|
||||
|
||||
Hario
|
||||
=====
|
||||
|
||||
For travel I will bring my `Hario Skerton <https://smile.amazon.com/gp/product/B001802PIQ/>`_, works great, super easy to clean. I usually don't change the grind setting while traveling so I don't complain about the annoying screw post to set it.
|
||||
|
||||
|
||||
****************
|
||||
Brewing Machines
|
||||
****************
|
||||
|
||||
Technivorm
|
||||
==========
|
||||
|
||||
For my daily coffee, I have a `Moccamaster Technivorm <https://us.moccamaster.com/collections/glass-carafe-brewers/products/kbgv-select>`_. My friend Andrey recommended it. It works extremely well and very consistent pours.
|
||||
|
||||
Chemex
|
||||
======
|
||||
|
||||
When I'm feeling fancy - or I'm trying a new coffee - I will break out my `Chemex <https://www.chemexcoffeemaker.com/eight-cup-classic-series-coffeemaker.html>`_. I do a 1:16 ratio of beans to water. I use the `Brown Paper Chemex Filters <https://www.chemexcoffeemaker.com/chemex-reg-bonded-filters-pre-folded-squares-natural.html>`_. I appreciate the bleached papers, but prefer unbleached.
|
||||
|
||||
Aeropress
|
||||
=========
|
||||
|
||||
For camping, I will bring my `Aeropress <https://aeropress.com/>`_. It's plastic, lightweight, and to my experience it is indestructible for travel.
|
||||
|
||||
French Press
|
||||
============
|
||||
|
||||
When I roast my own coffee, I like to experience it in multiple brewing methods. I have a `Bodum Bean French Press <https://luvtocook.com/products/ak11683-xyb-y16>`_ I got over a decade ago as a gift that has worked great. This one has an o-ring to seal the pouring spout, so the temperature chamber inside doesn't leak - a feature I like.
|
||||
|
||||
****************************
|
||||
Roasting Machines & Software
|
||||
****************************
|
||||
|
||||
FreshRoast SR700
|
||||
================
|
||||
|
||||
I have a **glorified popcorn maker** `SR700 <https://www.roastmasters.com/sr700.html>`_ as a roaster. I'm not the biggest fan of it, the built in software is a mess, the manual buttons on it are a nightmare to use. It **works**, I can only get consistent coffee out of it if I use OpenRoast. It has a USB port so you can control it with software.
|
||||
|
||||
OpenRoast
|
||||
=========
|
||||
|
||||
The `OpenRoast <https://github.com/Roastero/Openroast>`_ software is okay, but I don't have a temperature probe on my SR700, so I can only see "what is set" for temperature, and not get an accurate reading if I were using something like Artisan. I could set up a PID server on an arduino and plug into the usb port, but I feel at that rate I'd rather just buy a new roaster that works with better software. I do like OpenRoast is in Python so I can read and write the code.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
Notary Public
|
||||
#############
|
||||
:author: tyrel
|
||||
:category: Notary
|
||||
:tags: notary
|
||||
:status: published
|
||||
|
||||
Short update today.
|
||||
|
||||
I kept meaning to put together a way for people to utilize my notary services, so I finally made https://tyrel.bike/notary to redirect here to my Notary Public page.
|
||||
|
||||
I am a North Carolina Notary Public, and love helping my neighbors use my services.
|
||||
|
||||
If you're near me and need help - checkout `My Notary Page </pages/notary-public.html>`_.
|
|
@ -1,16 +0,0 @@
|
|||
Advent of Code 2022 + End of Year Updates
|
||||
=========================================
|
||||
:author: tyrel
|
||||
:category: Blog
|
||||
:tags: python, adventofcode, 6502, assembly, rust, go
|
||||
:status: published
|
||||
|
||||
Advent of Code this year is kicking my butt so I haven't been doing any tech blogging really lately. If you want to follow my progress, I think I might be done as of day 15 - This one seems to be a traveling salesman/knapsack problem related. Here's my repo: `https://gitea.tyrel.dev/tyrel/advent-of-code/src/branch/main/2022/python <https://gitea.tyrel.dev/tyrel/advent-of-code/src/branch/main/2022/python>`_.
|
||||
|
||||
I'm not on the computer that runs it, but I've been spending a lot of time playing with Apple's System7 in the BasiliskII emulator. Might have some fun projects with that coming up, but wanted to do some more learning before I start anything. So I have been going through a course on 6052 Assembly programming for the NES, and I'm about 73% done with that, it's really great!
|
||||
|
||||
It's By Gustavo Pezzi at `Pikuma <https://pikuma.com/courses/nes-game-programming-tutorial>`_, if "oldschool" programming floats your boat then I definitely recommend it. It's all programming through making roms with CC65/CA65 assembler, and using FCEUX to see your results, super neat.
|
||||
|
||||
I've been picking up some more Go work at work. My current team is sort of disbanding so I'm going to be moving away from doing just Python. It's been a year since I've done Go stuff, since I left Tidelift, so I'm really rusty.
|
||||
|
||||
Speaking of Rust, I was trying to do Advent of code in Rust also, and made it TWO whole days in Rust. It's still on my bucket of stuff to learn, but my free time seems to be running out lately, and I have a lot of things on my plate to get done.
|
|
@ -1,57 +0,0 @@
|
|||
Dotfiles - My 2022 Way
|
||||
######################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: dotfiles, macos, linux, nix, ubuntu,
|
||||
:status: published
|
||||
|
||||
New Year's eve eve, my main portable computer crashed. Rebooting to Safe mode, I could mount this MacBook's hard drive long enough to SCP the files over the network to my server, but I had to start that over twice because it fell asleep. I don't have access to rsync in the "Network Recovery Mode" it seems - maybe I should look to see if next time I can install things, it's moot now.
|
||||
|
||||
I spent all January 1st evening working on learning how Nix works. Of course, I started with Nix on macOS (intel at least) so I had to also learn how nix-darwin works. I have my `dotfiles <https://gitea.tyrel.dev/tyrel/dotfiles>`_ set up to use Nix now, rather than an `INSTALL.sh` file that just sets a bunch of symlinks.
|
||||
|
||||
I played around for a litle bit with different structures, but what I ended up with by the end of the weekend was two bash scripts (still working on makefile, env vars are being funky) one for each operating system `rebuild-macos.sh` and `rebuild-ubuntu.sh`. For now I'm only Nixifying one macOS system and two Ubuntu boxes. Avoiding it on my work m1 Mac laptop, as I don't want to have to deal with managing `synthetic.conf` and mount points on a work managed computer. No idea how JAMF and Nix will fight.
|
||||
|
||||
My filetree currently looks like (trimmed out a host and a bunch of files in `home/`)
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
.
|
||||
├── home
|
||||
│ ├── bin/
|
||||
│ ├── config/
|
||||
│ ├── gitconfig
|
||||
│ ├── gitignore
|
||||
│ ├── gpg/
|
||||
│ ├── hushlogin
|
||||
│ └── ssh/
|
||||
├── hosts/
|
||||
│ ├── _common/
|
||||
│ │ ├── fonts.nix
|
||||
│ │ ├── home.nix
|
||||
│ │ ├── programs.nix
|
||||
│ │ └── xdg.nix
|
||||
│ ├── ts-tl-mbp/
|
||||
│ │ ├── brew.nix
|
||||
│ │ ├── default.nix
|
||||
│ │ ├── flake.lock
|
||||
│ │ ├── flake.nix
|
||||
│ │ ├── home-manager.nix
|
||||
│ │ └── home.nix
|
||||
│ └── x1carbon-ubuntu/
|
||||
│ ├── default.nix
|
||||
│ ├── flake.lock
|
||||
│ ├── flake.nix
|
||||
│ ├── home-manager.nix
|
||||
│ └── home.nix
|
||||
├── rebuild-macos.sh
|
||||
└── rebuild-ubuntu.sh
|
||||
|
||||
Under `hosts/` as you can see, I have a `brew.nix <https://gitea.tyrel.dev/tyrel/dotfiles/src/branch/main/hosts/ts-tl-mbp/brew.nix>`_ file in my macbook pro's folder. This is how I install anything in homebrew. In my `flake.nix` for my macos folder I am using `home-manager`, `nix-darwin`, and `nixpkgs`. I provide this `brew.nix` to my `darwinConfigurations` and it will install anything I put in my `brew` nixfile.
|
||||
|
||||
I also have a `_common` directory in my `hosts`, this is things that are to be installed on EVERY machine. Things such as `bat`, `wget`, `fzf`, `fish`, etc. along with common symlinks and xdg-config links. My nvim and fish configs are installed and managed this way. Rather than need to maintain a neovim config for every different system, in the nix way, I can just manage it all in `_common/programs.nix`.
|
||||
|
||||
This is not "The Standard Way" to organize things, if you want more inspiration, I took a lot from my friend `Andrey's Nixfiles <https://github.com/shazow/nixfiles>`_. I was also chatting with him a bunch during this, so I was able to get three systems up and configured in a few days. After the first ubuntu box was configured, it was super easy to manage my others.
|
||||
|
||||
My `home/` directory is where I store my config files. My ssh public keys, my gpg public keys, my `~/.<dotfiles>` and my `~/.config/<files>`. This doesn't really need any explaination, but as an added benefit is I also decided to LUA-ify my nvim configs the same weekend. But that's a story for another time.
|
||||
|
||||
I am at this time choosing not to do NixOS - and relying on Ubuntu for managing my OS. I peeked into Andrey's files, and I really don't want to have to manage a full system configuration, drivers, etc. with Nix. Maybe for the future - when my Lenovo X1 Carbon dies and I need to reinstall that though.
|
|
@ -1,58 +0,0 @@
|
|||
TurboC2 Setting Header and Include Locations
|
||||
############################################
|
||||
:author: tyrel
|
||||
:category: DOS
|
||||
:tags: DOS, DOSBox, TurboC2, C
|
||||
:status: published
|
||||
|
||||
This weekend I purchased a book from this seller on Craigslist - `"Advanced MS-DOS Programming: The Microsoft Guide for Assembly Language and C Programmers" <https://www.librarything.com/work/178384>`_ and before opening it, I wanted to get a C environment running.
|
||||
|
||||
I found a copy of `TurboC2 on Archive.org <https://archive.org/details/msdos_borland_turbo_c_2.01>`_ and tossed that into my DOS Box install. I wrote a "Hello world" and pressed compile and it couldn't include "stdio.h", what the heck?
|
||||
|
||||
It seems that the Archive.org copy of Turbo C 2 ships with configuration that sets where the Includes and Lib directories to ``C:\TC``. I keep all my programs in ``C:\PROGS`` so of course it can't find any header files for me!
|
||||
|
||||
To fix this you can either move your TurboC install to ``C:\TC``, which feels wrong to me, or you could configure it in the options properly.
|
||||
|
||||
|
||||
|
||||
Steps
|
||||
~~~~~
|
||||
|
||||
* Go to the Directories entry in the Options Menu.
|
||||
* You can see the default provided configuration directories
|
||||
* Fill out your appropriate directories for all three of the options.
|
||||
* Make sure all three are configured properly.
|
||||
* Then you can save your config, so you only have to do this once.
|
||||
|
||||
|
||||
The Screenshot Way
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. figure:: {static}/images/2023/01/dosbox_1_environment_menu.png
|
||||
:alt: TurboC with the Options Menu selected and the Directories entry highlighted.
|
||||
|
||||
Go to the Directories entry in the Options Menu.
|
||||
|
||||
.. figure:: {static}/images/2023/01/dosbox_2_directories.png
|
||||
:alt: TurboC with a pop up, showing entries of Include Directories, Library Directories, and Turbo C Directory configured to C:\TC\INCLUDE C:\TC\LIB and C:\TC
|
||||
|
||||
You can see the default provided configuration directories
|
||||
|
||||
.. figure:: {static}/images/2023/01/dosbox_3_directories_edit.png
|
||||
:alt: TurboC with a pop up, showing C:\PROGS\TC\INCLUDE
|
||||
|
||||
Fill out your appropriate directories for all three of the options.
|
||||
|
||||
.. figure:: {static}/images/2023/01/dosbox_4_directories_filled.png
|
||||
:alt: TurboC with a pop up, showing entries of Include Directories, Library Directories, and Turbo C Directory configured to C:\PROGS\TC\INCLUDE C:\PROGS\TC\LIB and C:\PROGS\TC
|
||||
|
||||
Make sure all three are configured properly.
|
||||
|
||||
.. figure:: {static}/images/2023/01/dosbox_5_save_config.png
|
||||
:alt: TurboC with a popup showing a Save Options location of C:\PROGS\TC\TCCONFIG.TC
|
||||
|
||||
Then you can save your config, so you only have to do this once.
|
||||
|
||||
Unfortunately - this file is a binary file. You can't just edit it in a text editor and carry on, so this is the only way I know how to change these locations.
|
||||
|
||||
Hopefully this helps anyone else who runs into any include errors with Borland Turbo C 2!
|
|
@ -1,48 +0,0 @@
|
|||
6502 NES Course by Pikuma
|
||||
#########################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: 6502, assembly, NES
|
||||
:status: published
|
||||
|
||||
As I mentioned in my `December <https://tyrel.dev/blog/2022/12/advent-of-code-2022-end-of-year-updates.html>`_ post I'm doing a 6502 course on `Pikuma. <https://pikuma.com/courses/nes-game-programming-tutorial>`_
|
||||
|
||||
I'm about 75% of the way done, and I think I need to circle back to some earlier stuff about how the PPU works, but it's super fun.
|
||||
|
||||
Over the holidays I was able to stop at my father's and pick up my old NES.
|
||||
I swapped out the ZIF connector for a new one, and cleaned up some contacts on the RCA ports, and it works great!
|
||||
Once I found out that it was working - I played Sesame Street ABC 123, as that's the only one I had up in my office - I ordered an EverDrive N8.
|
||||
That came last week.
|
||||
|
||||
The pictures are tall due to how I took them, so sorry I'll attach them at the end of the post.
|
||||
|
||||
Once I got the `EverDrive N8 <https://krikzz.com/our-products/legacy/edn8-72pin.html>`_ I made sure it worked by playing a Battletoads ROM.
|
||||
Battletoad tested - I then copied Atlantico.NES to my Everdrive.
|
||||
Atlantico is the game that Gustavo is walking us through making in the current part of the course - not a real published game.
|
||||
I loaded it up and HOLY COW - something I actually wrote in Assembly is running on real hardware.
|
||||
|
||||
If you want to watch the video, it's very simplistic at the 75% mark, this was before the Collisions chapter, and no sound yet.
|
||||
|
||||
The feeling of getting something running, locally, and seeing it working on screen, despite being a programmer for ~~20 years, is AMAZING.
|
||||
Writing code that executes on the system you grew up playing the early 90's, wow.
|
||||
|
||||
I do wish the CRT TV my wife had was square, things get cut off on it.
|
||||
I even got a remote, so I could try to fix that in the menu, alas, only picture option is brightness.
|
||||
(Not that I realistically thought I could scale it, CRT Pixels are only Pixels.
|
||||
|
||||
----
|
||||
|
||||
Picture Gallery
|
||||
===============
|
||||
|
||||
Trying out putting all the pictures at the end of my posts, if they are not directly related to paragraph content.
|
||||
|
||||
.. figure:: {static}/images/2023/01/NES_Console.png
|
||||
:alt: An NES Console with the flap opened up. On top is a Zapper gun with another controller, both with cables neatly wrapped up. On the floor, plugged in, in front of the NES, is another controller. The Power LED is on.
|
||||
|
||||
My NES plugged in and running.
|
||||
|
||||
.. figure:: {static}/images/2023/01/NES_Atlantico.png
|
||||
:alt: A CRT TV screen with a game running on it. In 8bit graphics, the game is a ship sailing to the right, with planes flying to the left. Some missiles are shooting up.
|
||||
|
||||
Atlantico game. There may be some interference with scanlines causing moire patterns, sorry.
|
|
@ -1,22 +0,0 @@
|
|||
I have been hit by Malware.
|
||||
###########################
|
||||
:author: tyrel
|
||||
:category: Website
|
||||
:tags: malware
|
||||
:status: published
|
||||
|
||||
This morning I woke up to an email from DigitalOcean saying they have scanned my host and on port 8080 was botnet.
|
||||
|
||||
"We are writing to let you know that your Droplet tyrelsouza.com at 138.197.14.67 is a Command & Control server part of a botnet."
|
||||
|
||||
UGH. This is not what I wanted to have to deal with today.
|
||||
|
||||
My first steps were to shut down all php things (the issue is with heysrv.php in EVERY directory). Then I ran ``find / -name heysrv.php -delete`` to delete all the files. After this, I decommissioned my pixelfed instance (rip pix.tyrel.dev) and disabled the startup scripts for that.
|
||||
|
||||
I then installed Simply Static on my one `remaining wordpress <https://k3tas.radio/airband/>`_ and turned that into a static collecton of html and related files. This elimiated two php instances. With one more remaining - my Mediawiki server.
|
||||
|
||||
I found an Export Pages link and now have an XML file of all my pages (only 78 or so) and can start working on putting this back to html notes on my joplin tool, instead of my wiki. Before I shut it down for good, I need to extract all the images, that's the only thing that's left to keep this knowledge secure.
|
||||
|
||||
Now the only thing left on this server is this static blog, pushed up from pelican. Everything else on this machine is just ``index.php`` files that redirect around (example `https://tyrel.bike/ <https://tyrel.bike>`_ to my Strava)
|
||||
|
||||
It's a bit sad I had to do this today, when I have other things I want to deal with - but DigitalOcean gave me a 24 hour ultimatum. I'll rebuild this server later, but for now, blog on!
|
|
@ -1,13 +0,0 @@
|
|||
Brand New Server
|
||||
################
|
||||
:author: tyrel
|
||||
:category: Blog
|
||||
:tags: blog
|
||||
:status: published
|
||||
|
||||
Per my last post, I did not succeed in cleaning off the malware.
|
||||
|
||||
That machine is dead and I am now running on a $4/mo Digital Ocean droplet - much less power than before, but I don't really need it anymore now that I have my own server at home.
|
||||
|
||||
I am sad I don't have a Pixelfed anymore, maybe I'll relaunch it some day.
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
Now Page
|
||||
########
|
||||
:author: tyrel
|
||||
:category: blog
|
||||
:tags: blog
|
||||
:status: published
|
||||
|
||||
My friend Nik showed me his ``/now/`` page, and I find that a cool idea.
|
||||
This blog is more of a technical braindump than a log of my personal life, so I don't really talk about my life much.
|
||||
|
||||
I assume no one will visit `https://tyrel.dev/now <https://tyrel.dev/now/>`_ but if you do, you will see a handcrafted update of my life and what has happend with me lately.
|
||||
|
||||
Thanks to Derek Sivers for setting up a network of ``/now/`` pages! `https://nownownow.com/ <https://nownownow.com/about>`_.
|
|
@ -1,22 +0,0 @@
|
|||
Emulation
|
||||
#########
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: emulation
|
||||
:status: published
|
||||
|
||||
I haven't had much time lately for blog posts, I've been dealing with bed time routines with my newborn, and once those are done, I get a few hours of alone time for computer things.
|
||||
|
||||
Lately I've been toying around with Amiga OS, FreeDOS, Windows 95, and Apple IIe things.
|
||||
|
||||
I got a raspberry pi and installed Pimiga, got a fun set up and that was neat. I then installed Amiberry on my macbook, with some remote hard drive images on my samba share, and I have a consistent setup for Amiga on any machine in the house or on tailscale.
|
||||
|
||||
I then decided to install FreeDOS to a barely used Dell Vostro 1720 and install to that. It works great, I have WordStar, TurboC, and more installed and it's fun to get back to my roots in that way.
|
||||
|
||||
After that I decided to install Windows 95 with 86Box, did the same with remote hard disk images, and got that running. Been toying around in Visual Basic 6, Oh the memories!! I installed that so I could play Lego City, but having voodoo graphics errors I need to figure out before I can play.
|
||||
|
||||
I also ordered an Apple IIe emulator machine that runs on an Esp8266 from `CT6502 <https://ct6502.org/product/mfa2-32emu/>`_ and it works great. So cool just tossing a disk image on the MicroSD card and loading it up. The downside to this is I can't figure out how to swap disks in realtime, so I can't play Ultima, or any multi disk games. I can however load .hdv files so if something comes with a hard disk image.
|
||||
|
||||
Not really much for a tech post, and nothing to share codewise, but thought I'd break some radio silence. I also imported my flying blog here, so I added the Flying category/tags.
|
||||
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
Neovim, Nix, Telescope, Tree-sitter, Mason
|
||||
##########################################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: nix, nvim, rust
|
||||
:status: published
|
||||
|
||||
I made a mistake with not reading CHANGELOGs for all my packages in Neovim this week. This sent me down a small rabbit hole trying to fix all the things.
|
||||
|
||||
What happened is I ran ``:PackerUpdate`` which, pulls the latest version of Packer packages, good, updates! But... Telescope has a new requirement on main branch that requires Neovim 0.9.0. The problem is that the latest NixPkgs for Neovim right now is 0.8.1. I ran to google, tried to set an overlay to use ``neovim-nightly``, but that didn't work. If you recall in `Dotfiles - My 2022 Way <https://tyrel.dev/blog/2023/01/dotfiles-my-2022-way.html>`_ I'm not actually using NixOS so (please correct me if I'm wrong) overlays don't work. I tried specifing a version in my ``programs.nix``, I tried a bunch of other things at 1AM that I don't remember anymore.
|
||||
|
||||
Almost ripped it all out just to use Nvim 0.9.0 on this machine until NixPkgs has updated the repo. I decided that was the wrong idea, and went to sleep.
|
||||
|
||||
Tonight, I was able to figure out that in Packer, you can pin a commit!
|
||||
|
||||
It's clear in the docs, but I was trying to fix it at the Nix level, so I didn't immediately think of this, even though at my last job, Tidelift, I was doing package pinning analysis! Derp.
|
||||
|
||||
So, I added ``commit="c1a2af0"`` to my ``use`` statment in ``plugins.lua`` and Telescope started working again without a warning, or issue. `Commit <https://gitea.tyrel.dev/tyrel/dotfiles/commit/eb32c2194aba355afec80e647bb4df31a3e40c73>`_.
|
||||
|
||||
That wasn't the only problem though. In my infinite wisdom, I followed some reddit posts that I won't link to, that suggested deleting ``~/.local/share/nvim`` and rerunning ``PackerInstall``, the problem there -- my tree-sitter configs are in my nix files.
|
||||
|
||||
This is an issue I need to look at later, but in my `programs.nix <https://gitea.tyrel.dev/tyrel/dotfiles/src/commit/eb32c2194aba355afec80e647bb4df31a3e40c73/hosts/_common/programs.nix#L26-L32>`_ file, I some reason have two entries of ``plugins =``. I had to uncomment the first one where I inject tree-sitter, and comment out the second setting. Then rebuild my nix flakes.
|
||||
|
||||
After that,I had to comment the first, uncomment the second, and rebuild with ``withAllGrammars`` config.
|
||||
|
||||
This worked, I had my rust tree-sitter configs working, but was missing ``rust-analyzer``.
|
||||
|
||||
That's in Mason! So I ran ``:Mason``, found ``rust-analyzer`` slapped that ``i`` button, and I finally had my system back after 2 days of issues.
|
||||
|
||||
This was mostly a blogpost so I can reference back to it in the future, but hopefully at least _someone_ learns to pin your dang nvim Packages!
|
|
@ -1,35 +0,0 @@
|
|||
Set Environment Variables with LastPass
|
||||
#######################################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: bash, automation, work
|
||||
:status: published
|
||||
|
||||
I have to use LastPass at work, and I store some API keys in there. Rather than copy/paste and have the actual api key on my terminal, I like to use ``read -rs ENV_VAR_NAME`` to set environment variables, so they are hidden from scrollback.
|
||||
|
||||
Recently my coworker set something up that we need an environment variable set up for running some Terraform commands. I don't feel like pasting it in every time from LastPass, so I figured out how to set this up and automate it. I'm sure I've already talked a lot about how I love ``direnv`` and I maintain a lot of different ``.envrc`` files for work things. For my last team I had one per repo! Well ``direnv`` comes to the rescue again.
|
||||
|
||||
* The first step is installing the `lastpass-cli <https://github.com/lastpass/lastpass-cli>`_.
|
||||
* Then you need to set it up so you log in, how you do that is up to you. I have lpass checking status, and if it exits nonzero, then running lpass login again in my direnv.
|
||||
* After that you can use ``lpass show`` and capture that in a variable to export your API key as an environment variable.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
lpass status
|
||||
if [ $? -ne 0 ]; then
|
||||
lpass login email@address.com
|
||||
fi
|
||||
export API_KEY=$(lpass show "Secret-Name-Here" --password)
|
||||
|
||||
Example ``.envrc`` file.
|
||||
|
||||
|
||||
I love automating things, and when a coworker says "oh no we have to do this"... I run to automate it!
|
||||
|
||||
|
||||
Resources
|
||||
~~~~~~~~~
|
||||
|
||||
* LastPass CLI https://github.com/lastpass/lastpass-cli
|
||||
* Direnv https://github.com/direnv/direnv
|
|
@ -1,28 +0,0 @@
|
|||
pfSense
|
||||
#######
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: networking
|
||||
:status: published
|
||||
|
||||
This week I finally got a machine that is solely to run pfSense.
|
||||
I didn't want to spend _too_ much money so I bought a $200.00 Qotom Firewall Q330G4.
|
||||
This was great and easy to set up.
|
||||
|
||||
First I bought a Netgear WAC104 and installed OpenWRT on it. Simple enough.
|
||||
Then I put that into bridge mode, so it's just an Access Point and not a "smart" router too.
|
||||
|
||||
Then I put my Linksys EA9300 into bridge mode and behind the pfSense machine (into a switch) and couldn't access any of my server's sites.
|
||||
|
||||
After futzing with that for a couple days, I finally figured out the problem.
|
||||
I thought I was behind a double NAT, but I wasn't. When I moved my EA9300 from my sole WiFi router, to behind the pfSense machine, I neglected to change some settings on my AT&T modem.
|
||||
|
||||
You see — dear reader— when I set up this network on my AT&T Modem, I had to enable Passthrough mode.
|
||||
This, was set to a MAC Address, not an IP Address.
|
||||
So when I was making sure to keep my IP network on the same 192.168.1.1/24, I thought that was all I needed.
|
||||
|
||||
Alas, there's a dropdown to pick the MAC address of the machine that everything passes through.
|
||||
I can now access my bookmarks, notes, ebooks, and plex server!
|
||||
|
||||
|
||||
Thanks to my friend Daniel (@sanitybit) - who was a great rubber duck and gave me some pointers when I was debugging, and also helped me find the hardware for the pfSense box!
|
|
@ -1,18 +0,0 @@
|
|||
Netgear WAC104
|
||||
##############
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: networking
|
||||
:status: published
|
||||
|
||||
I recently bought four Netgear WAC104 devices, and am flashing OpenWRT onto them.
|
||||
I have struggled a lot to get the firmware on, due to the not great interface they provide.
|
||||
|
||||
The issue is, that it prompts you to change the password, but then when you change it on the page you land on, nothing connects anymore and you can't access the router.
|
||||
|
||||
The solution is to click "Set Password" in the Administration menu on the left, and set it there.
|
||||
Even though there is a prompt to set the password on every page, that will change other settings too and break things.
|
||||
|
||||
The router isn't great, and the software is awful so thats why I'm installing OpenWRT anyway.
|
||||
|
||||
Two down, two more to go!
|
|
@ -1,20 +0,0 @@
|
|||
Laid Off - 2023 Edition!
|
||||
########################
|
||||
:author: tyrel
|
||||
:category: Personal
|
||||
:tags: work
|
||||
:status: published
|
||||
|
||||
"Hey Tyrel, I put a meeting on your calendar, let me know if you can make it." The last words you want to hear from your manager.
|
||||
|
||||
Well it happened again, and I got caught in some layoffs from work and am on the job hunt again. I did want to be able to spend more time with Astrid, but not like this!
|
||||
|
||||
After the call with HR and them all explaining what was happening, and panic texting my wife and some friends. I emailed the recruiters I've been working with for a few weeks back, and all day today I've been appling to a lot of places.
|
||||
|
||||
There are a LOT of jobs out there I'm not interested in, a lot of Ruby on Rails jobs, crypto companies, etc. But I am finding a LOT of Python or Go jobs I'm applying to. I'd love to get a job doing rust and firmware work, but that's unlikely as I want to stay remote, and I have very minimal Rust experience.
|
||||
|
||||
What worries me is finding health insurance, because America ties it to work... my wife is unemployed and now we have to cancel a few appointments for us the next few weeks. Still going to keep Astrids 4mo vaccinations though. Those I'll be okay paying out of pocket for.
|
||||
|
||||
I just ended the day applying to twelve jobs, hopefully one pans out!
|
||||
|
||||
If anyone needs any Python consultation, let me know too! Thanks!
|
|
@ -1,10 +0,0 @@
|
|||
I am now Matrix Compatible
|
||||
##########################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: matrix
|
||||
:status: published
|
||||
|
||||
You can now message me on Matrix using `@tyrel:tyrel.dev <https://matrix.to/#/@tyrel:tyrel.dev>`_.
|
||||
|
||||
I'm running Synapse.
|
|
@ -1,23 +0,0 @@
|
|||
General Job Search Update
|
||||
#########################
|
||||
:author: tyrel
|
||||
:category: Personal
|
||||
:tags: work
|
||||
:status: published
|
||||
|
||||
As mentioned in a previous post, I'm on the job hunt again.
|
||||
I got laid off in June with a 30% Reduction In Force.
|
||||
|
||||
I've been searching primarily for Python and Go roles, but I'm not having a lot of luck right now - seems everyone else also got laid off is who I am competing against.
|
||||
`(That said, go hire my friend Nik! He's fantastic!) <https://nkantar.com/blog/2023/08/hire-me-v202308/>`_
|
||||
I've had a lot of job opportunity people ghost me.
|
||||
Gotten through a few late rounds, only to never hear from the company again.
|
||||
Even if I have emailed them a thank you letter for the interviews, to express my interest.
|
||||
|
||||
I've been around professionally for thirteen years.
|
||||
Over those years, I have picked up mostly back end skills.
|
||||
I have eight solid years of Django experience.
|
||||
Four years of Ruby on Rails experience.
|
||||
A couple years of Flask, FastAPI, and other smaller Python Frameworks mixed in.
|
||||
|
||||
I'm looking for an IC role, where I can move into a Tech Lead role. I want to eventually some day be a Staff/Principal role, but I don't have that on paper to show I can do it, so trying to get in somewhere new with an IC role.
|
|
@ -1,128 +0,0 @@
|
|||
My Life Story
|
||||
#############
|
||||
:author: tyrel
|
||||
:category: Personal
|
||||
:tags: life
|
||||
:status: published
|
||||
|
||||
Trying to write a more prose version of my Resume.
|
||||
Kind of a living post about my life in the Software Engineering World.
|
||||
|
||||
Early Life
|
||||
----------
|
||||
|
||||
I started programming with Visual Basic in the 90s on a laptop in my father's car.
|
||||
Parents had just divorced and the drive to his new place every other weekend was two hours, so I had a lot of downtime going through the Visual Basic 5 and 6 books we had.
|
||||
After that, I started trying to program chat bots for Starcraft Battle.net, and irc bots.
|
||||
In highschool I started taking more Visual Basic courses, mostly because that's all that my teachers had for classes.
|
||||
Senior year I took some Early Education courses at the local college, and then went to that college (Keene State) for my Computer Science Degree.
|
||||
At Keene State, I took a lot of Java classes, that was the core curriculum.
|
||||
I also took some more Visual Basic courses, some C++ and web design courses as well.
|
||||
|
||||
After college, I thought I'd be working Java again, but I got a referral from one of my favorite professors to this company called Appropriate Solutions Inc, and started working in Python/Django.
|
||||
I had never touched Python outside of OpenRPG - and even then it was just installing the interpretor so I could run the game.
|
||||
|
||||
Appropriate Solutions Inc
|
||||
-------------------------
|
||||
|
||||
At Appropriate Solutions I worked on maybe ten different projects.
|
||||
The first thing I worked on was an Hour Tracker to learn how Django works, it worked great, but definitley didn't look too flashy.
|
||||
From there, I went on to work on a Real Estate Website, a Bus tracking/mapping system for a school district, a Pinterest Clone, and some more GIS mapping things.
|
||||
One of our projects was with HubSpot, and I went to one of their hackathons, and a couple conferences in Boston.
|
||||
I had a lot of friends in Boston, so I decided to move there mid 2012.
|
||||
|
||||
Propel Marketing
|
||||
----------------
|
||||
|
||||
I got my first Boston job in Quincy, MA - working at a startup called Propel Marketing.
|
||||
This was also a Python/Django role, but had more front end work.
|
||||
While there I worked on their internal CMS tooling for selling white labeld websites to clients.
|
||||
I worked on a lot of internal tooling, one that would pull leads from our system, and then upload to a lot of different vendor tooling.
|
||||
A couple of Python PIL tools that would generate facebook and twitter banners, but a lot of the work there was learning and writing tests in Python.
|
||||
|
||||
Akamai
|
||||
------
|
||||
|
||||
From there, I started a six month contract at Akamai, working for their Tech Marketing team on a couple tools.
|
||||
This later got extended another three months, until the team ran out of budget for contractors.
|
||||
I worked on their `"Spinning Globe" <https://gnet.akamai.com/>`_ which was really fun.
|
||||
Some internal dashboards, and a couple email tools that worked with SalesForce.
|
||||
|
||||
Addgene
|
||||
-------
|
||||
|
||||
In 2015 I then landed a spot at Addgene - a nonprofit biotech!
|
||||
This is where my career really started taking off.
|
||||
I started to lead projects, do more valuable research and go to conferences.
|
||||
The company itself was - for my tenure there - two Django Projects and some jQuery/Bootstrap.
|
||||
The "core" site was the ecommerce and research site.
|
||||
Buying, selling, research on Plasmids and Viruses.
|
||||
The back end was the inventory management system.
|
||||
|
||||
While there, I also lead the charge on a couple projects.
|
||||
We were migrating to AWS - from an in house rackmount server, so we needed to get a lot of data on S3.
|
||||
Testing at Addgene was fickle, as everything was stored in tsv files and reloaded in memory.
|
||||
I developed a python package that would save thousands of dollars of S3 costs, while still making the file upload process in testing seamless.
|
||||
`Django DBFileStorage <https://gitlab.com/Tyrel/django-dbfilestorage>`_ was born.
|
||||
|
||||
Another charge I lead was helping Celigo alpha test Integrator.IO - working on building an integration of a lot of our sales data into netsuite/salesforce (I forget which one) by working with the Celigo API.
|
||||
This was a fun project - as when I was done with this, we got to archive an old Java repo that was barely hanging on, and had no bugfixes in years.
|
||||
|
||||
While at Addgene, I also started the "Teaching Scientists How To Program" lunch and learn club.
|
||||
We would have meetings where anyone from the Scientist team could come, ask questions about Python, and work through any of the problems they were having with our Jupyter Notebooks we set up that they could run.
|
||||
This was great, I helped foster some friendships that I believe will last a lifetime, helped people transition into actual programmers, and helped the company save a lot of time by helping more people learn.
|
||||
|
||||
Tidelift
|
||||
--------
|
||||
|
||||
After Addgene, in 2018 I joined an early stage startup called Tidelift.
|
||||
I was one of the first engineers there, so I got to help lead a lot of early shaping of the company.
|
||||
I started with working on a lot of the `Lifter <https://tidelift.com/about/lifter>`_ focused side of the site.
|
||||
Helping create tasks the lifters could complete so they could get paid.
|
||||
From there working on the Subscriber side of things where the paying clients would get information about their dependencies.
|
||||
I have an upcoming blog post about some work there, so I won't go into too much details.
|
||||
I did help start the Tidelift CLI though.
|
||||
A tool written in Go, it was a CI/CD tool to analyze software dependencies for security/licensing problems
|
||||
|
||||
|
||||
EverQuote
|
||||
---------
|
||||
After Tidelift, I started at EverQuote in 2022.
|
||||
My longtime friend Sam was a Director leading a team that was working on replatforming a monolith and needed to backfill a python role.
|
||||
I had been asking him for years when he would work on Python stuff, as he had only been working at Ruby companies for the past few years, so this caught my ear and I started there.
|
||||
|
||||
The first project was replatforming a Python 2.7 monolith - with code from as far back as 2010 - to micro services.
|
||||
These were mainly FastAPI services, that communicted amongst eachother with kafka.
|
||||
Some of them would read from the database, and send events into the kafka stream.
|
||||
Some would read from the stream, and write to the database.
|
||||
Others would read from database or kafka, and then communicate with a third party system.
|
||||
|
||||
All of these had Grafana (and later NewRelic) metrics attached.
|
||||
Every server had at least one dashboard, with many graphs, event logs and charts.
|
||||
These were all deployed using kubernetes, terraform, AWS.
|
||||
I can't speak to the specifics about past there - as there was another dedicated ops team.
|
||||
|
||||
Some other projects I worked on there were really fun.
|
||||
One of the analysts used to maintain her daily workflow in a google doc, and I helped lead a project that took that apart and worked on it programatically.
|
||||
This was then turned into a five part rebalancing, reweighting, and email route manipulating script - that ran daily using Cron, and saved that team over fourteen hours a week.
|
||||
|
||||
The Remarketing team came to an end, and there was a small re-org and we merged with another team and became the Consumer Engagement team.
|
||||
This dealt with Calls, SMS, Email, and working with the Sales Reps.
|
||||
|
||||
We started a project using Go and React that would pull users from the database and show a script for the Sales rep to read to the client on the phone, with specific information about what plans were available.
|
||||
Other projects on that team, which is what I spent most of my time on, was porting CI/CD processes from Atlassian Bamboo, to GitHub Actions.
|
||||
|
||||
During this time, I took a couple months of paternity leave, and a few weeks after I came back there was a major reduction in force and I was laid off.
|
||||
|
||||
|
||||
After EverQuote
|
||||
---------------
|
||||
|
||||
Since leaving EQ, I have been on the job hunt.
|
||||
If you know anything about tech in 2023, a LOT of people are job hunting right now.
|
||||
I'm excited that this happened at a time in my daughter's life where I can spend SO MUCH more time with her than some fathers can.
|
||||
That's the good side of things.
|
||||
I hope I get a job soon though, as the sole earner in my family.
|
||||
|
||||
If you've made it this far, please check out my Resume in the sidebar, and contact me if you have anything you think would be a fit.
|
||||
Who knows, I might delete this last section once I get a job!
|
|
@ -1,40 +0,0 @@
|
|||
Which which is which?
|
||||
#####################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: linux, macos, zsh
|
||||
:status: published
|
||||
|
||||
I had a bit of a "Tyrel you know nothing" moment today with some commandline tooling.
|
||||
|
||||
I have been an avid user of ZSH for a decade now, but recently I tried to swap to fish shell.
|
||||
Along the years, I've maintained a lot of different iterations of `dotfiles <https://gitea.tyrel.dev/tyrel/dotfiles>`_, and shell aliases/functions.
|
||||
I was talking to a `friend <https://fredeb.dev>`_ [citation needed] about updating from ``exa`` to ``eza`` and then noticed I didn't have my aliases loaded, so I was still using ``ls`` directly, as I have ``alias ls="exa -lhFgxUm --git --time-style long-iso --group-directories-first"`` in my ``.shell_aliases`` file.
|
||||
|
||||
I did this by showing the following output:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ which ls
|
||||
/usr/bin/ls
|
||||
|
||||
Because I expected it to show me which alias was being pointed to by ``ls``.
|
||||
|
||||
My friend pointed out that "Which doesn't show aliases, it only points to files" to which I replied along the lines of "What? No way, I've used ``which`` to show me aliases and functions loads of times."
|
||||
|
||||
And promptly sent a screenshot of my system NOT showing that for other aliases I have set up. Things then got conversational and me being confused, to the point of me questioning if "Had I ever successfully done that? Maybe my macbook is set up differrently" and went and grabbed that.
|
||||
|
||||
Friend then looked at the man page for which, and noticed that there's the ``--read-alias`` and ``--read-functions`` flags on ``which``, and I didn't have those set.
|
||||
I then swapped over to bash "Maybe it's a bash thing only? I'm using Fish".
|
||||
|
||||
Nope, still nothing! Then went to google, and it turns out that ZSH is what has this setup by default.
|
||||
Thank you `"Althorion" <https://stackoverflow.com/a/14196212>`_ from Stackoverflow for settling my "Yes you've done this before" confusion.
|
||||
|
||||
It turns out that ZSH's ``which`` is equivalent to the ZSH shell built-in ``whence -c`` which shows aliases and functions.
|
||||
|
||||
After running ``/usr/bin/zsh`` and sourcing my aliases (I don't have a zshrc file anymore, I need to set that back up), I was able to settle my fears and prove to myself that I wasn't making things up. There is a which which shows you which aliases you have set up, which is default for ZSH.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ which ls
|
||||
ls: aliased to exa -lhFgxUm --git --time-style long-iso --group-directories-first
|
|
@ -1,93 +0,0 @@
|
|||
Rotate a Matrix in Python
|
||||
#########################
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: python
|
||||
:status: published
|
||||
|
||||
I've been doing Advent of Code for a few years now, and every year I do it in my favorite language, Python.
|
||||
One thing that comes up a lot, is rotating matrices.
|
||||
|
||||
One way to do this, is to use Numpy, using ``np.rot90(mat)``, but not everyone wants to install Numpy just to do one small task.
|
||||
I know I don't always.
|
||||
|
||||
The way I always do it, that will support non-square matrixes, is to use zip.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> matrix = [
|
||||
[1,2,3],
|
||||
[4,5,6],
|
||||
[7,8,9]
|
||||
]
|
||||
>>> rotated = list(zip(*matrix[::-1]))
|
||||
# And result is
|
||||
[[7, 4, 1],
|
||||
[8, 5, 2],
|
||||
[9, 6, 3]]
|
||||
|
||||
We can break this down bit by bit.
|
||||
|
||||
This will copy the list, with a -1 step, resulting in a reverse order
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> matrix[::-1]
|
||||
[[7,8,9],
|
||||
[4,5,6],
|
||||
[1,2,3]]
|
||||
|
||||
Next we need to call zip in order to get the x-th item from each inner list, but first, we need to unpack it. If you'll notice, the unpacked version isn't wrapped with another list, which is what zip needs from us.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Too many lists
|
||||
>>> print(matrix[::-1])
|
||||
[[7, 8, 9], [4, 5, 6], [1, 2, 3]]
|
||||
|
||||
# Just right
|
||||
>>> print(*matrix[::-1])
|
||||
[7, 8, 9] [4, 5, 6] [1, 2, 3]
|
||||
|
||||
From there, we can pass this unpacked list of - in our case - three lists, to zip (and in Python 3 this returns a generator, so we need to call list again on it, or just use it)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> # Again, we get the rotated matrix
|
||||
>>> list(zip(*matrix[::-1]))
|
||||
[[7, 4, 1],
|
||||
[8, 5, 2],
|
||||
[9, 6, 3]]
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Small note: If you run this, you will actually get a list of tuples, so you can map those back to a list, if you need to update them for any reason.
|
||||
I just wanted square brackets in my examples.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# This is just messy looking, so I didn't mention it until now
|
||||
>>> list(map(list, zip(*matrix[::-1])))
|
||||
|
||||
|
||||
As I mentioned, due to using ``zip`` this will work with non-square examples as well.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> matrix = [
|
||||
... [1,2,3,4,5,6,7,8,9],
|
||||
... [9,8,7,6,5,4,3,2,1],
|
||||
... ]
|
||||
>>> print(list(zip(*matrix[::-1])))
|
||||
[(9, 1),
|
||||
(8, 2),
|
||||
(7, 3),
|
||||
(6, 4),
|
||||
(5, 5),
|
||||
(4, 6),
|
||||
(3, 7),
|
||||
(2, 8),
|
||||
(1, 9)]
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
Djangocon 2023
|
||||
##############
|
||||
:author: tyrel
|
||||
:category: Tech
|
||||
:tags: django, conferences
|
||||
:status: published
|
||||
|
||||
I am at DjangoCon 2023 this year!
|
||||
|
||||
I live in Durham, NC and have been avoiding conferences for the past few years because of Covid and not wanting to travel.
|
||||
This year for, what ever reason, they picked Durham!
|
||||
|
||||
So I am breaking my "Don't go to conferences" for multiple reasons.
|
||||
|
||||
1) The DSF has pretty great Covid rules, and mask requirements.
|
||||
2) Testing requirements.
|
||||
3) It's local, so I get to sleep in my own bed.
|
||||
|
||||
I'm not guaranteed to get to see my daughter, but I hope she knows I still love her even if I'm not around.
|
||||
I'm leaving at 7:30 tomorrow as I'm biking in, and she may be asleep.
|
||||
|
||||
Already I've gone to one of the local breweries I haven't gone to yet (See above: Covid), and met some great people, can't wait for the rest of the week.
|
||||
|
||||
While technically a "Tech Blog" I am by no means a great note taker, so don't expect any quality information from me in blog form, I'm mostly going for the HallwayTrack, and to watch talks.
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
What I've been up to since October
|
||||
##################################
|
||||
:author: tyrel
|
||||
:category: Personal
|
||||
:tags: personal
|
||||
:status: published
|
||||
|
||||
Since my last post, about Djangocon I've been pretty MIA. I think I mentioned I got a job, at REDLattice. I've been doing some Django, and other misc programming, and it's been pretty neat. It's a security company, so I haven't really been able to talk about what I've been doing.
|
||||
|
||||
It's nice to be back where I'm comfortable, in my tech stack.
|
||||
|
||||
I also have been picking up some side projects again, taking some classes, running, and more.
|
||||
|
||||
I ran a 5k last month that was on a runway (KGSO) - that was fun. I got sub 30 minutes, but my heart rate spiked REALLY high because it was cold and rainy, not a pleasant race. I really need to work on my running, my average is usually 185, which for a 36yo is awful. I was running slowly for a bit and got it down to a 165 average, but took a week off from runnning because of hurting my foot with a cut.
|
||||
|
||||
Gustavo Pezzi released another course on his Pikuma platform - this time it's Playstation 1 programming in C and MIPS. I don't really have the best foundation in C despite doing C++ a lot in college and before - so I've picked up his Graphics Programming from Scratch course. I really enjoy the way he teaches, he never rushes ahead thinking you know something.
|
||||
|
||||
One thing I realized is in college I never really did much advanced algebra, so I've decided to also take a Linear Alebra course from MIT's Open Courseware MIT 18.06. Reading math text books is definitely different than I remember, but it might just be this professor. I wish I had some friends doing this course with me, I need to be held accountable.
|
||||
|
||||
For other projects I've gotten some new wood tools lately - I traded a watch for them - so I have some ideas in mind now that I have a planer.
|
||||
|
||||
Other than that, my daughter turned ONE last month! The day before I turned 36. We had a big party for me, her, and our niece. The party was fun, but I def am not the best party host.
|
||||
|
||||
We're taking our first flight as a family next week, hopefully Astrid's not too loud. I was this age when I flew down to Florida and we found out I had hearing issues, so I'm worried for that.
|
||||
|
||||
Not much else is new, but felt like it's been time for a blog post recently, even if it's just a personal post.
|
|
@ -1,9 +1,9 @@
|
|||
Neighbor's Water Heater Automation (part 1)
|
||||
###########################################
|
||||
Neighbor's Water Heater Automation
|
||||
##################################
|
||||
:author: tyrel
|
||||
:category: Automation
|
||||
:category: automation
|
||||
:tags: automation, c++, esp8266, servo, stepper
|
||||
:status: published
|
||||
:status: draft
|
||||
|
||||
The Setting
|
||||
~~~~~~~~~~~
|
||||
|
@ -26,11 +26,6 @@ The Lay Of The Land
|
|||
He has a `Bosch Tronic 6000C <https://www.prowaterheatersupply.com/PDFS/Bosch_Tronic_6000C_Pro_WH27_WH17_Installation_Manual.pdf>`_, with what appears to be a rotary encoder knob to set the temperature.
|
||||
I only spent a few minutes under his house while planning this and didn't think to any measuring of how many detents to rotate, or how long the dial took to rotate to 120°F, so my first pass of this project is done with estimations.
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_heater.png
|
||||
:alt: bosch heater with a temperature 7 segment LED set to 120F
|
||||
:width: 920px
|
||||
|
||||
|
||||
Project Time - Round 1!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -57,9 +52,6 @@ This held how many seconds after pressing Higher or Lower, that I would send the
|
|||
This seemed to work relatively well, but I figure I should just use a stepper motor if I was attempting to emulate one this way.
|
||||
I dug around in my closet and was able to find some parts.
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_servo.png
|
||||
:alt: blue case servo with a white arm, cables running off screen. sitting on a desk.
|
||||
|
||||
Project Time - Round 2!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -82,16 +74,6 @@ I then apply a multiplier (TBD also... there's a lot of these as you can see!) a
|
|||
|
||||
The endpoint ``/initialize`` runs ``stepper.moveTo`` with ten rotations CCW, and then resets the "known location" back to zero (this also runs on power on for now).
|
||||
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_webpage.png
|
||||
:alt: webpage controls, title "Water Heater Control", a blue slider with a green button saying "Set Temperature: 90", and red "Initialize to 90" button
|
||||
:width: 920px
|
||||
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_stepper.png
|
||||
:alt: blue case servo with a white arm, cables running off screen. sitting on a desk.
|
||||
:width: 920px
|
||||
|
||||
In Action
|
||||
~~~~~~~~~
|
||||
|
||||
|
@ -105,10 +87,6 @@ Programming wise, I need to figure out how many steps is one degree. Is the rota
|
|||
|
||||
Stay tuned to find out the exciting conclusion once I can go down below Frank's house.
|
||||
|
||||
.. figure:: {static}/images/2022/11/04_stepper_wheel.png
|
||||
:alt: blue case servo with a white arm, cables running off screen. sitting on a desk.
|
||||
:width: 920px
|
||||
|
||||
Code
|
||||
~~~~
|
||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 393 KiB |
Before Width: | Height: | Size: 410 KiB |
Before Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 490 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 765 KiB |
Before Width: | Height: | Size: 609 KiB |
Before Width: | Height: | Size: 693 KiB |
Before Width: | Height: | Size: 630 KiB |
Before Width: | Height: | Size: 795 KiB |
Before Width: | Height: | Size: 222 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 294 KiB |
Before Width: | Height: | Size: 315 KiB |
Before Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 346 KiB |
Before Width: | Height: | Size: 158 KiB |
Before Width: | Height: | Size: 420 KiB |
Before Width: | Height: | Size: 311 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 462 KiB |
Before Width: | Height: | Size: 439 KiB |
Before Width: | Height: | Size: 537 KiB |
Before Width: | Height: | Size: 351 KiB |
Before Width: | Height: | Size: 498 KiB |
Before Width: | Height: | Size: 283 KiB |
Before Width: | Height: | Size: 414 KiB |
Before Width: | Height: | Size: 135 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 341 KiB |