{
    "version": "https://jsonfeed.org/version/1",
    "title": "negativesign",
    "home_page_url": "https://negativesign.com/",
    "feed_url": "https://negativesign.com/index.json",
    "author": {
        "name": "Andrew Catellier"
    },
    
    "items": [
         {
                "title": "Modeling a Desk Shelf Using Onshape for iPad",
                "id": "https://negativesign.com/blog/2023/09/04/modeling-a-desk-shelf-using-onshape-for-ipad/",
                "url": "https://negativesign.com/blog/2023/09/04/modeling-a-desk-shelf-using-onshape-for-ipad/",
                "summary": "Having watched an absurd amount of Home Office Youtube, I was thinking about how I could improve my office. I wanted a desk shelf, but they seemed really expensive for what they were. And because I want to do fascinating, fun, and weird things, I thought it might be fun to build one with my Dad. In true Leeroy Jenkins fashion, I decided I was going to build a model and make drawings of a desk shelf in some CAD program.",
                
                "content_html": "\u003cp\u003eHaving watched an absurd amount of \u003ca href=\"https://www.youtube.com/watch?v=NWvS37wLShE\"\u003eHome Office Youtube\u003c/a\u003e, I was thinking about how I could improve my office. I wanted a desk shelf, but they seemed really expensive for what they were. And \u003ca href=\"https://negativesign.com/blog/2023/09/02/sorry-for-blogging/\"\u003ebecause I want to do fascinating, fun, and weird things\u003c/a\u003e, I thought it might be fun to build one with my Dad. In true Leeroy Jenkins fashion, I decided I was going to build a model and make drawings of a desk shelf in some CAD program. But on an iPad. Because.\u003c/p\u003e\n\n\u003cp\u003eIn the past I avoided CAD and fabrication projects because I was being really stupid\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e and refused to learn a new thing. But CAD is WAY more approachable than I thought it would be.\u003csup class=\"footnote-ref\" id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e The fundamental concepts aren\u0026rsquo;t that hard to learn if you give yourself the space to do so.\u003c/p\u003e\n\n\u003cp\u003eI decided to try \u003ca href=\"https://www.onshape.com/en/\"\u003eOnshape\u003c/a\u003e because I could sign up for a free account and they had an iPad app. I installed the app on my iPad and started \u003ca href=\"https://youtu.be/3ejyMFSrwhU\"\u003emaking sketches, extruding\u003c/a\u003e, intersecting, \u003ca href=\"https://youtu.be/8JUaBy5-GGo\"\u003eassembling\u003c/a\u003e, and \u003ca href=\"https://youtu.be/s7eDXbqDdnA\"\u003eexploding\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eOverall the experience of building models was not too cumbersome. I didn\u0026rsquo;t have my keyboard attached, so there was a lot of menu juggling. The iPad app does in fact have keyboard shortcuts, but part of the appeal for me was using the iPad in tablet mode. I enjoyed being able to manipulate the model with my fingers and making fine adjustments and selections with my pencil.\u003c/p\u003e\n\n\u003cp\u003eThe models turned out well! But when building things with wood, you build them from drawings, not models. Unfortunately, it\u0026rsquo;s not possible to generate drawings on the iPad—they must currently be generated using the web interface. Bummer! Generating the drawings on my 2017 MacBook Pro was a little painful due to UI input lag, but that\u0026rsquo;s an old computer and this \u003cem\u003eis\u003c/em\u003e full-blown CAD \u003cem\u003ein a browser\u003c/em\u003e. Once completed, though, it\u0026rsquo;s easy to generate PDFs of the drawings and then share them.\u003c/p\u003e\n\n\u003cp\u003eI like the idea that anybody could create an Onshape account and collaborate on a project together. One limitation of a free Onshape account is that all of your projects are \u0026ldquo;public.\u0026rdquo; I say \u0026ldquo;public\u0026rdquo; because if you want to view somebody else\u0026rsquo;s project, you must have an account. Links to models are not accessible unless you log in. I haven\u0026rsquo;t done lots of exploring on their web app, but given that restriction, I\u0026rsquo;m not totally certain how somebody would discover your account or models.\u003c/p\u003e\n\n\u003cp\u003eThe Onshape website talks about how they\u0026rsquo;re the fastest-growing, uh, CAD community or whatever, and I bet it\u0026rsquo;s because of their requirement to create an account to interact with their product at all. But hey, if MAU isn\u0026rsquo;t growing as much as your investors expect, you\u0026rsquo;ve gotta do something.\u003c/p\u003e\n\n\u003cp\u003eOnshape was great but I\u0026rsquo;m not married to it. Next time, I\u0026rsquo;ll look for a different product and see if I can complete the entire workflow without leaving the iPad and without paying an absurd price for personal projects.\u003c/p\u003e\n\n\u003cp\u003eOh, and if you want some drawings for a desk shelf that resembles a product that retails for pert-near $400, reach out.\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eThis is always true. And if it\u0026rsquo;s not, something is very wrong.\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003eThat said, my only real CAD experience was with Drafix Windows CAD back in the early 90s when I was like 11?\n \u003ca class=\"footnote-return\" href=\"#fnref:2\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": "Having watched an absurd amount of Home Office Youtube, I was thinking about how I could improve my office. I wanted a desk shelf, but they seemed really expensive for what they were. And because I want to do fascinating, fun, and weird things, I thought it might be fun to build one with my Dad. In true Leeroy Jenkins fashion, I decided I was going to build a model and make drawings of a desk shelf in some CAD program. But on an iPad. Because.\nIn the past I avoided CAD and fabrication projects because I was being really stupid1 and refused to learn a new thing. But CAD is WAY more approachable than I thought it would be.2 The fundamental concepts aren\u0026rsquo;t that hard to learn if you give yourself the space to do so.\nI decided to try Onshape because I could sign up for a free account and they had an iPad app. I installed the app on my iPad and started making sketches, extruding, intersecting, assembling, and exploding.\nOverall the experience of building models was not too cumbersome. I didn\u0026rsquo;t have my keyboard attached, so there was a lot of menu juggling. The iPad app does in fact have keyboard shortcuts, but part of the appeal for me was using the iPad in tablet mode. I enjoyed being able to manipulate the model with my fingers and making fine adjustments and selections with my pencil.\nThe models turned out well! But when building things with wood, you build them from drawings, not models. Unfortunately, it\u0026rsquo;s not possible to generate drawings on the iPad—they must currently be generated using the web interface. Bummer! Generating the drawings on my 2017 MacBook Pro was a little painful due to UI input lag, but that\u0026rsquo;s an old computer and this is full-blown CAD in a browser. Once completed, though, it\u0026rsquo;s easy to generate PDFs of the drawings and then share them.\nI like the idea that anybody could create an Onshape account and collaborate on a project together. One limitation of a free Onshape account is that all of your projects are \u0026ldquo;public.\u0026rdquo; I say \u0026ldquo;public\u0026rdquo; because if you want to view somebody else\u0026rsquo;s project, you must have an account. Links to models are not accessible unless you log in. I haven\u0026rsquo;t done lots of exploring on their web app, but given that restriction, I\u0026rsquo;m not totally certain how somebody would discover your account or models.\nThe Onshape website talks about how they\u0026rsquo;re the fastest-growing, uh, CAD community or whatever, and I bet it\u0026rsquo;s because of their requirement to create an account to interact with their product at all. But hey, if MAU isn\u0026rsquo;t growing as much as your investors expect, you\u0026rsquo;ve gotta do something.\nOnshape was great but I\u0026rsquo;m not married to it. Next time, I\u0026rsquo;ll look for a different product and see if I can complete the entire workflow without leaving the iPad and without paying an absurd price for personal projects.\nOh, and if you want some drawings for a desk shelf that resembles a product that retails for pert-near $400, reach out.\n This is always true. And if it\u0026rsquo;s not, something is very wrong. [return] That said, my only real CAD experience was with Drafix Windows CAD back in the early 90s when I was like 11? [return]   ",
                "date_published": "2023-09-04T21:30:00-06:00"
            }
            , {
                "title": "Momma Turkey",
                "id": "https://negativesign.com/blog/2023/09/03/momma-turkey/",
                "url": "https://negativesign.com/blog/2023/09/03/momma-turkey/",
                "summary": "A delicious cocktail inspired by a turkey parade in the fall. Invented by Shorty.\nIngredients  one slice candied ginger one orange dash of Angostura bitters 1 tsp vanilla extract 1\u0026frasl;2 tbsp agave syrup 1 oz Benedictine \u0026amp; Brandy (B\u0026amp;B) 3 oz bourbon (wild turkey?) cinnamon stick ice  Preparation  In a cocktail shaker, muddle candied ginger and two 1\u0026frasl;2 inch strips of orange peel. Squeeze 2 tbsp of orange juice into the shaker.",
                
                "content_html": "\n\n\u003cp\u003eA delicious cocktail inspired by a turkey parade in the fall. Invented by Shorty.\u003c/p\u003e\n\n\u003ch3 id=\"ingredients\"\u003eIngredients\u003c/h3\u003e\n\n\u003cul\u003e\n\u003cli\u003eone slice candied ginger\u003c/li\u003e\n\u003cli\u003eone orange\u003c/li\u003e\n\u003cli\u003edash of Angostura bitters\u003c/li\u003e\n\u003cli\u003e1 tsp vanilla extract\u003c/li\u003e\n\u003cli\u003e\u003csup\u003e1\u003c/sup\u003e\u0026frasl;\u003csub\u003e2\u003c/sub\u003e tbsp agave syrup\u003c/li\u003e\n\u003cli\u003e1 oz Benedictine \u0026amp; Brandy (B\u0026amp;B)\u003c/li\u003e\n\u003cli\u003e3 oz bourbon (wild turkey?)\u003c/li\u003e\n\u003cli\u003ecinnamon stick\u003c/li\u003e\n\u003cli\u003eice\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"preparation\"\u003ePreparation\u003c/h3\u003e\n\n\u003col\u003e\n\u003cli\u003eIn a cocktail shaker, muddle candied ginger and two \u003csup\u003e1\u003c/sup\u003e\u0026frasl;\u003csub\u003e2\u003c/sub\u003e inch strips of orange peel.\u003c/li\u003e\n\u003cli\u003eSqueeze 2 tbsp of orange juice into the shaker.\u003c/li\u003e\n\u003cli\u003eAdd a dash of Angostura bitters, the vanilla extract, and agave syrup. Muddle it dawg.\u003c/li\u003e\n\u003cli\u003eAdd B\u0026amp;B and bourbon and stir 20 times or until all liquid ingredients have sufficiently mixed.\u003c/li\u003e\n\u003cli\u003eAdd ice. Stir 30-45 seconds.\u003c/li\u003e\n\u003cli\u003eUse a lighter to ignite the cinnamon stick until smoking and cover with serving glass until the cinnamon stick stops smoking.\u003c/li\u003e\n\u003cli\u003eUse a strainer to pour the shaker into the serving glass and garnish with orange peel.\u003c/li\u003e\n\u003c/ol\u003e\n",
                "content_text": " A delicious cocktail inspired by a turkey parade in the fall. Invented by Shorty.\nIngredients  one slice candied ginger one orange dash of Angostura bitters 1 tsp vanilla extract 1\u0026frasl;2 tbsp agave syrup 1 oz Benedictine \u0026amp; Brandy (B\u0026amp;B) 3 oz bourbon (wild turkey?) cinnamon stick ice  Preparation  In a cocktail shaker, muddle candied ginger and two 1\u0026frasl;2 inch strips of orange peel. Squeeze 2 tbsp of orange juice into the shaker. Add a dash of Angostura bitters, the vanilla extract, and agave syrup. Muddle it dawg. Add B\u0026amp;B and bourbon and stir 20 times or until all liquid ingredients have sufficiently mixed. Add ice. Stir 30-45 seconds. Use a lighter to ignite the cinnamon stick until smoking and cover with serving glass until the cinnamon stick stops smoking. Use a strainer to pour the shaker into the serving glass and garnish with orange peel.  ",
                "date_published": "2023-09-03T19:56:42-06:00"
            }
            , {
                "title": "Sorry for Blogging",
                "id": "https://negativesign.com/blog/2023/09/02/sorry-for-blogging/",
                "url": "https://negativesign.com/blog/2023/09/02/sorry-for-blogging/",
                "summary": "I came back to ye olde static site generator after three years and I think everything is still working. Not only that, the contraption I set up to post from my iPad still works too. It\u0026rsquo;s a miracle. At least until I have to update go.mod or whatever. Or I realize that my VPC got backdoored and has secretly been mining crypto without my knowledge.\nAnyway, Hugo is fine I guess.",
                
                "content_html": "\u003cp\u003eI came back to ye olde static site generator after three years and I think everything is still working. Not only that, the contraption I set up to post from my iPad still works too. It\u0026rsquo;s a miracle. At least until I have to update \u003ccode\u003ego.mod\u003c/code\u003e or whatever. Or I realize that my VPC got backdoored and has secretly been mining crypto without my knowledge.\u003c/p\u003e\n\n\u003cp\u003eAnyway, Hugo is fine I guess. I chose it because I wanted \u003ca href=\"https://negativesign.com/blog/2018/07/09/its-been-real-octopress/\"\u003eto publish Jupyter notebooks\u003c/a\u003e but then I proceeded to post about running JupyterHub in an NVIDIA container and restarting a computer into a different OS using \u003ccode\u003egrub\u003c/code\u003e and some other things that are utterly useless now, 4-5 years later, but resulted in some inbound requests to write for other people\u0026rsquo;s blogs? No Jupyter notebooks though.\u003c/p\u003e\n\n\u003cp\u003eAlso there were the yearly summaries. I love doing those, but I sort of preconditioned doing them on the completion of publishing daily photos for that year, and I am now three years behind on that.\u003c/p\u003e\n\n\u003cp\u003eWha happen? Well, from some time in 2018 until earlier this year, I had two simultaneous jobs. Also there were small things like the pandemic, the Cameron Peak fire, family health issues, I got a new day job, and some other events. Most of whatever time was left went into Job #2, where I built on top of \u003ca href=\"https://negativesign.com/blog/2020/05/06/what-is-it-that-you-do-here./\"\u003ethis cool neural network audio quality predictor thingy\u003c/a\u003e and \u003ca href=\"https://arxiv.org/abs/2206.13272\"\u003edocumented it\u003c/a\u003e in what I really hope will be published as a journal article soon.\u003c/p\u003e\n\n\u003cp\u003eWhile all that was happening, I watched people \u003ca href=\"https://www.youtube.com/@scottmanley\"\u003eprepare themselves to fly in space\u003c/a\u003e, \u003ca href=\"https://www.youtube.com/channel/UCILl8ozWuxnFYXIe2svjHhg\"\u003ebuild actual rockets from scratch\u003c/a\u003e, \u003ca href=\"https://www.theverge.com/23076663/nebula-youtube-creator-business-future-startup-ceo-dave-wiskus\"\u003ebuild an entire video streaming platform\u003c/a\u003e, \u003ca href=\"https://www.youtube.com/watch?v=6SYT0upjNac\"\u003epower their tesla using turbine engines (??)\u003c/a\u003e, and all kinds of other fascinating, fun, and weird things\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e. It made me think about all the things I\u0026rsquo;ve wanted build, write, and make. I wanna do fascinating, fun, and weird things too! And I guess I want people to know about it, which is weird, but you know.\u003c/p\u003e\n\n\u003cp\u003eSo here I am again.\u003c/p\u003e\n\n\u003cp\u003ePlease like and subscribe and tell me what weird thing I should build in the comments below.\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eDid you know there\u0026rsquo;s an entire cottage industry of people who \u003ca href=\"https://www.youtube.com/watch?v=NWvS37wLShE\"\u003emake videos to sell home office products\u003c/a\u003e?? And a lawyer who only \u003ca href=\"https://www.youtube.com/watch?v=GncYzuRMtb8\"\u003eposts videos about lock picking\u003c/a\u003e?\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": "I came back to ye olde static site generator after three years and I think everything is still working. Not only that, the contraption I set up to post from my iPad still works too. It\u0026rsquo;s a miracle. At least until I have to update go.mod or whatever. Or I realize that my VPC got backdoored and has secretly been mining crypto without my knowledge.\nAnyway, Hugo is fine I guess. I chose it because I wanted to publish Jupyter notebooks but then I proceeded to post about running JupyterHub in an NVIDIA container and restarting a computer into a different OS using grub and some other things that are utterly useless now, 4-5 years later, but resulted in some inbound requests to write for other people\u0026rsquo;s blogs? No Jupyter notebooks though.\nAlso there were the yearly summaries. I love doing those, but I sort of preconditioned doing them on the completion of publishing daily photos for that year, and I am now three years behind on that.\nWha happen? Well, from some time in 2018 until earlier this year, I had two simultaneous jobs. Also there were small things like the pandemic, the Cameron Peak fire, family health issues, I got a new day job, and some other events. Most of whatever time was left went into Job #2, where I built on top of this cool neural network audio quality predictor thingy and documented it in what I really hope will be published as a journal article soon.\nWhile all that was happening, I watched people prepare themselves to fly in space, build actual rockets from scratch, build an entire video streaming platform, power their tesla using turbine engines (??), and all kinds of other fascinating, fun, and weird things1. It made me think about all the things I\u0026rsquo;ve wanted build, write, and make. I wanna do fascinating, fun, and weird things too! And I guess I want people to know about it, which is weird, but you know.\nSo here I am again.\nPlease like and subscribe and tell me what weird thing I should build in the comments below.\n Did you know there\u0026rsquo;s an entire cottage industry of people who make videos to sell home office products?? And a lawyer who only posts videos about lock picking? [return]   ",
                "date_published": "2023-09-02T15:38:36-06:00"
            }
            , {
                "title": "The Ground Beneath my Feet and the Sky Above my Head",
                "id": "https://negativesign.com/blog/2020/12/20/the-ground-beneath-my-feet-and-the-sky-above-my-head/",
                "url": "https://negativesign.com/blog/2020/12/20/the-ground-beneath-my-feet-and-the-sky-above-my-head/",
                "summary": "I\u0026rsquo;ve been trying to take and publish at least one photo for every day since 2010. Ten years, roughly, as of December 2019. I\u0026rsquo;ve published this diary on my website, and I\u0026rsquo;ve written about the project at least once before. From my first selfie with (taken with a Canon T2i) to the last photo of 2019 (taken with a Leica M10!), I published 8,564 photos for this project—an average of 2.",
                
                "content_html": "\u003cp\u003e\u003cimg src=\"/images/ground_and_sky@2x.jpg\" alt=\"the ground beneath my feet and the sky above my head\" /\u003e\u003c/p\u003e\n\n\u003cp\u003eI\u0026rsquo;ve been trying to take and publish at least one photo for every day since 2010. Ten years, roughly, as of December 2019. I\u0026rsquo;ve \u003ca href=\"https://thisisreal.net/imglib/#Past_Days\"\u003epublished this diary on my website\u003c/a\u003e, and I\u0026rsquo;ve \u003ca href=\"https://thisisreal.net/imglib/#Past_Days\"\u003ewritten about the project\u003c/a\u003e at least once before. From my \u003ca href=\"https://thisisreal.net/faceit/catchup/1/\"\u003efirst selfie\u003c/a\u003e with (taken with a Canon T2i) to the \u003ca href=\"https://thisisreal.net/2019/12/31/5\"\u003elast photo of 2019\u003c/a\u003e (taken with a Leica M10!), I published 8,564 photos for this project—an average of 2.3 photos per day.\u003c/p\u003e\n\n\u003cp\u003eGenerating this document that chronicles ten years of my life has certainly been some kind of accomplishment. I sometimes struggle, though, to understand why I\u0026rsquo;ve continued to build this record. Partially, I admire \u003ca href=\"https://chrisglass.com/album/\"\u003ethe work\u003c/a\u003e \u003ca href=\"https://yournewfavorite.com\"\u003eothers\u003c/a\u003e \u003ca href=\"https://www.flickr.com/photos/laurenfarmer/sets/72157622986263253/\"\u003ehave done\u003c/a\u003e in this area and want to make something even a small fraction as interesting. Partially, I\u0026rsquo;m vain. Partially, it\u0026rsquo;s an instinct I can\u0026rsquo;t shake.\u003c/p\u003e\n\n\u003cp\u003eThis record of my life is both a memory aide and a memory censor. The photos I take and any text I write to accompany them necessarily highlight certain events at the expense of others. Even if the images I publish jog my memory and bring undocumented events to my mind, that historical context vanishes at the interface of my consciousness and the world around me.\u003c/p\u003e\n\n\u003cp\u003eI suppose every person processes this existential tautology in their own way. Personally, I can\u0026rsquo;t yet improve on the \u003ca href=\"https://thisisreal.net/thoughts/catchup/17/\"\u003etext I wrote to accompany this image five years ago\u003c/a\u003e:\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"/images/inner_storm@2x.jpg\" alt=\"inner storm\" /\u003e\u003c/p\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003einner storm\u003c/p\u003e\n\n\u003cp\u003ethe idea that the human body and mind are in some sense a temporal reflection is beautiful, perplexing and terrifying to me.\u003c/p\u003e\n\n\u003cp\u003eit’s disappointing how poorly we parse these reflections. to some extent we can forgive ourselves—the reflection itself is a hopelessly incomplete representation.\u003c/p\u003e\n\n\u003cp\u003eeven so, i can’t help but wonder if we are getting better, or if we will.\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\u003cp\u003eThe photo processing speedrun I recently completed for 2019 reinforced this notion. I published almost 1,700 photos for 2019, but in many cases there was more than a year between taking a photo and publishing it. As my mind time-traveled through 2020 it somehow managed to forget parts of 2019 and ignore other parts. When I was finally able to process and publish photos from 2019 I remembered things that happened, remembered thoughts that I had, and realized just how much I had forgotten. No documentation effort, no matter how thorough, can effectively communicate the fullness of one\u0026rsquo;s life experience. Even to oneself.\u003c/p\u003e\n\n\u003cp\u003eIn the \u003ca href=\"https://www.youtube.com/watch?v=0eBpjZZnukg\"\u003e2018 Ignite Boulder talk\u003c/a\u003e that I gave on this very topic I touched on the futility of documentation projects like this. I said this futility is both merciful and cruel. Good, bad, and mundane are all placed on the ambivalent altar of entropy.\u003c/p\u003e\n\n\u003cp\u003eBut I\u0026rsquo;m still doing it and I plan to continue. It\u0026rsquo;s worth the time and effort. Taking photos forces me to participate in the present. It makes me consider what I\u0026rsquo;ll remember. Perhaps most importantly though, \u003ca href=\"https://thisisreal.net/thoughts/catchup/7/\"\u003eit gives the gift of hindsight and forces me to confront my actions in a context outside of my present understanding.\u003c/a\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003cimg src=\"/images/nocturnal@2x.jpg\" alt=\"nocturnal\" /\u003e\u003c/p\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003esometimes i think it would be nice to have some cognizance of the implications of any given passing moment, but in those instants i remind myself that fully understanding the present is an act of theft against my future self.\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\u003cp\u003e\u0026ldquo;If you can not measure it, you can not improve it.\u0026rdquo;\u003c/p\u003e\n\n\u003cp\u003eMay I never stop measuring.\u003c/p\u003e\n",
                "content_text": "I\u0026rsquo;ve been trying to take and publish at least one photo for every day since 2010. Ten years, roughly, as of December 2019. I\u0026rsquo;ve published this diary on my website, and I\u0026rsquo;ve written about the project at least once before. From my first selfie with (taken with a Canon T2i) to the last photo of 2019 (taken with a Leica M10!), I published 8,564 photos for this project—an average of 2.3 photos per day.\nGenerating this document that chronicles ten years of my life has certainly been some kind of accomplishment. I sometimes struggle, though, to understand why I\u0026rsquo;ve continued to build this record. Partially, I admire the work others have done in this area and want to make something even a small fraction as interesting. Partially, I\u0026rsquo;m vain. Partially, it\u0026rsquo;s an instinct I can\u0026rsquo;t shake.\nThis record of my life is both a memory aide and a memory censor. The photos I take and any text I write to accompany them necessarily highlight certain events at the expense of others. Even if the images I publish jog my memory and bring undocumented events to my mind, that historical context vanishes at the interface of my consciousness and the world around me.\nI suppose every person processes this existential tautology in their own way. Personally, I can\u0026rsquo;t yet improve on the text I wrote to accompany this image five years ago:\n inner storm\nthe idea that the human body and mind are in some sense a temporal reflection is beautiful, perplexing and terrifying to me.\nit’s disappointing how poorly we parse these reflections. to some extent we can forgive ourselves—the reflection itself is a hopelessly incomplete representation.\neven so, i can’t help but wonder if we are getting better, or if we will.\n The photo processing speedrun I recently completed for 2019 reinforced this notion. I published almost 1,700 photos for 2019, but in many cases there was more than a year between taking a photo and publishing it. As my mind time-traveled through 2020 it somehow managed to forget parts of 2019 and ignore other parts. When I was finally able to process and publish photos from 2019 I remembered things that happened, remembered thoughts that I had, and realized just how much I had forgotten. No documentation effort, no matter how thorough, can effectively communicate the fullness of one\u0026rsquo;s life experience. Even to oneself.\nIn the 2018 Ignite Boulder talk that I gave on this very topic I touched on the futility of documentation projects like this. I said this futility is both merciful and cruel. Good, bad, and mundane are all placed on the ambivalent altar of entropy.\nBut I\u0026rsquo;m still doing it and I plan to continue. It\u0026rsquo;s worth the time and effort. Taking photos forces me to participate in the present. It makes me consider what I\u0026rsquo;ll remember. Perhaps most importantly though, it gives the gift of hindsight and forces me to confront my actions in a context outside of my present understanding.\n sometimes i think it would be nice to have some cognizance of the implications of any given passing moment, but in those instants i remind myself that fully understanding the present is an act of theft against my future self.\n \u0026ldquo;If you can not measure it, you can not improve it.\u0026rdquo;\nMay I never stop measuring.\n",
                "date_published": "2020-12-20T23:35:44-07:00"
            }
            , {
                "title": "2019 in Review",
                "id": "https://negativesign.com/blog/2020/12/13/2019-in-review/",
                "url": "https://negativesign.com/blog/2020/12/13/2019-in-review/",
                "summary": "Another year, another year-end-review, I always say. Thankful to have an opportunity to reflect on another trip around the sun. You may think it\u0026rsquo;s odd to write a review of 2019 in December of 2020, but if y\u0026rsquo;all have 2020ed at all, you understand how remembering 2019 could be therapeutic.\nIf you asked me, my friends, my family, or anyone adjacent to my life, you\u0026rsquo;d know that the main theme of my 2019 was work.",
                
                "content_html": "\u003cp\u003eAnother year, \u003ca href=\"https://negativesign.com/blog/2017/12/31/2017-in-review/\"\u003eanother\u003c/a\u003e \u003ca href=\"https://negativesign.com/blog/2019/01/13/2018-in-review/\"\u003eyear-end-review\u003c/a\u003e, I always say. Thankful to have an opportunity to reflect on another trip around the sun. You may think it\u0026rsquo;s odd to write a review of 2019 in December of 2020, but if y\u0026rsquo;all have 2020ed at all, you understand how remembering 2019 could be therapeutic.\u003c/p\u003e\n\n\u003cp\u003eIf you asked me, my friends, my family, or anyone adjacent to my life, you\u0026rsquo;d know that the main theme of my 2019 was work. My day job has been as intense as ever. We\u0026rsquo;re a small company and being a small company comes with growing pains. But we have accomplished so much more than you\u0026rsquo;d expect for a 3-4 person engineering team.\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eWe \u003ca href=\"https://thisisreal.net/2019/01/24/\"\u003ebuilt\u003c/a\u003e, \u003ca href=\"https://thisisreal.net/2019/02/13/\"\u003etested\u003c/a\u003e, and \u003ca href=\"https://thisisreal.net/2019/04/01/\"\u003edeployed\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/08/05/\"\u003ethree\u003c/a\u003e (!) sensor packages. These sensor packages imaged thousands of acres at a ridiculously high resolution. Hardware is hard. Remotely debugging hardware is hard. I learned so much.\u003c/li\u003e\n\u003cli\u003eI \u003ca href=\"https://thisisreal.net/2019/03/25/\"\u003eautomated the GNSS post-processing workflow\u003c/a\u003e because I didn\u0026rsquo;t know any better. It took a huge amount of work, but the workflow is finally relatively stable and robust.\u003c/li\u003e\n\u003cli\u003eI, again, did tons of sysadmin and IT work. \u003ca href=\"https://thisisreal.net/2019/12/05/\"\u003eTons of it\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eI got to work on a grant awarded by a prestigious government agency.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eWhile going through my 2019 work journal, I realized how little work I did that relates to my official title (and my career goals) and I\u0026rsquo;m frustrated about that. Even so, I encountered challenges and solved them because they needed to be solved. The passing of time has revealed just how difficult some of those challenges actually were. Many days I completed a legitimately absurd number of tasks. Often, I would go on to put in a couple hours for my second job as well. I did, however, manage to get set up to \u003ca href=\"https://thisisreal.net/2019/01/28/\"\u003ework from home\u003c/a\u003e—this has turned out to be important.\u003c/p\u003e\n\n\u003cp\u003eThe majority of my spare time was spent on my \u003ca href=\"https://thisisreal.net/2019/03/01/\"\u003eside hustle\u003c/a\u003e with the goals of attending ICASSP 2020 in Barcelona and trying to grow the old savings account as much as possible. In the process, and with help from my \u003ca href=\"https://thisisreal.net/2019/03/21/\"\u003eesteemed colleague\u003c/a\u003e, I built an \u003ca href=\"https://negativesign.com/blog/2020/05/06/what-is-it-that-you-do-here./\"\u003eaccurate no-reference speech quality estimator\u003c/a\u003e—a thing that\u0026rsquo;s been sort of a holy grail in the speech processing field for decades. If you asked me whether or not this was possible even 5 years ago, I would have said, \u0026ldquo;no\u0026rdquo;. In our second iteration reduced the number of parameters in the model by \u0026gt;99% \u003cem\u003eand\u003c/em\u003e improved robustness. We \u003ca href=\"https://thisisreal.net/2019/05/10/\"\u003ewrote\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2019/06/21/\"\u003esubmitted\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/10/25/\"\u003etwo papers\u003c/a\u003e, and the second ended up being accepted to ICASSP 2020 (mission accomplished!). I am proud of this, full stop. I am proud I was able to accomplish this in my spare time.\u003c/p\u003e\n\n\u003cp\u003eEven though I spent so much time working, I really think I managed to wring everything I possibly could have out of 2019. When I wasn\u0026rsquo;t working, I:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eStarted \u003ca href=\"https://thisisreal.net/2019/01/05/\"\u003eediting my photos\u003c/a\u003e on an \u003ca href=\"https://thisisreal.net/2019/03/07/\"\u003eiPad\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eSpent quality time on the mountain\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/04/13/\"\u003eAte amazing food, tolerated the dog, stared at the clouds\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/04/14/\"\u003eSaw the first signs of Spring\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/05/04/\"\u003eHad hammock and burrito time\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/05/19/\"\u003eGot socked in\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/06/15/\"\u003eBasked in the green\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/06/29/\"\u003eSmelled the waldflaurs\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/05/\"\u003eOgled the clouds\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/01/\"\u003eEnjoyed the snow\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eGot some workouts in until \u003ca href=\"https://thisisreal.net/2019/02/27/\"\u003emy gym closed 😪\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/03/29/\"\u003eSaw Antonio Sanchez (and co.) perform at the Boulder Theater\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eWent on a few hikes\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/04/20/\"\u003ePalisade Mountain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/06/30/\"\u003eStorm Mountain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/27/\"\u003eGot soaked on Crosier Mountain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/15/\"\u003eOuray\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/17/\"\u003eTelluride\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/29/\"\u003eUtah\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eSpent time with friends\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/06/07/\"\u003eWent to Chicago\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/06/08/\"\u003eto visit\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/06/09/\"\u003eSteven and Jeena\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/31/\"\u003eHiked around Crosier mountain\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/09/20/\"\u003eA going away party for Mark\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/10/18/\"\u003eDylan\u0026rsquo;s birthday party\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/09/\"\u003eDrinks with Dustin and Carly\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/24/\"\u003eBrunch with the Denver crew\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/21/\"\u003eBike rides around Boulder with Brian\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eSpent time with family\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/01/26/\"\u003eWent to Steamboat\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/02/23/\"\u003ewith my Dad\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/04/06/\"\u003ea few times\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/04/\"\u003eCelebrated the 4th of July\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/14/\"\u003eMountain time with Christina\u0026rsquo;s mom\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/09/28/\"\u003eBuilt a retaining wall\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/26/\"\u003eWent to Utah\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/11/27/\"\u003eto see my sister\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2019/11/28/\"\u003ebrother-in-law for Thanksgiving\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/24/\"\u003eHome to Cheyenne\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/12/25/\"\u003efor Christmas\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/04/09/\"\u003eWatched Christina give a talk about her work\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/06/03/\"\u003eWent to eyeo\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/06/04/\"\u003efor the second time\u003c/a\u003e—\u003ca href=\"https://thisisreal.net/2019/06/05/\"\u003eextreme\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/06/06/\"\u003espiritual refreshment\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eManaged to write four \u003ca href=\"https://negativesign.com\"\u003eblog posts\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/02/26/\"\u003ePrinted out all my 2018 averages\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eAte some amazing food, drank delicous drinks\n\n\u003cul\u003e\n\u003cli\u003eAt Mateo (\u003ca href=\"https://thisisreal.net/2019/04/04/\"\u003emmm, fries\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003eMany delicious meals made by Christina, but specifically these \u003ca href=\"https://thisisreal.net/2019/12/08/\"\u003ebiscuits and gravy\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/10/23/\"\u003ePizza at Backcountry\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/19/\"\u003eWork meeting with Charles at Burn\u0026rsquo;s Pub\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/01/27/\"\u003eDocumented\u003c/a\u003e some \u003ca href=\"https://thisisreal.net/2019/08/03/\"\u003econstruction\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2019/10/08/\"\u003echange\u003c/a\u003e in \u003ca href=\"https://thisisreal.net/2019/10/16/\"\u003eBoulder\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eAttended at least 20 meetups\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/03/12/\"\u003eWork in Progress\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/01/\"\u003eDenver Creative Tech\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/09/16/\"\u003eB.E.A.T.\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/06/\"\u003eAnalyze Boulder\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/11/12/\"\u003eBoulder Python\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/12/\"\u003eIgnite Boulder\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/talks/20190709_boulder_python/\"\u003eGave a talk about Docker\u003c/a\u003e at \u003ca href=\"https://thisisreal.net/2019/07/09/\"\u003eBoulder Python\u003c/a\u003e—(I am looking through this talk again and cracking myself up)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/13/\"\u003eGot a new Nintendo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/07/21/\"\u003eAttended\u003c/a\u003e my \u003ca href=\"https://thisisreal.net/2019/07/31/\"\u003efavorite\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/08/07/\"\u003electure series\u003c/a\u003e, \u003ca href=\"https://thisisreal.net/2019/08/21/\"\u003eMixed Taste\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/15/\"\u003eTraveled to Ouray\u003c/a\u003e, \u003ca href=\"https://thisisreal.net/2019/08/18/\"\u003eTelluride\u003c/a\u003e, \u003ca href=\"https://thisisreal.net/2019/08/19/\"\u003eGrand Junction\u003c/a\u003e, and \u003ca href=\"https://thisisreal.net/2019/08/20/\"\u003ePalisade\u003c/a\u003e and got some good eating, drinking, and mountain biking in\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/08/27/\"\u003eSaw\u003c/a\u003e the \u003ca href=\"https://thisisreal.net/2019/08/30/\"\u003eClark Richert\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/09/11/\"\u003eexhibits\u003c/a\u003e as \u003ca href=\"https://thisisreal.net/2019/09/13/\"\u003emany times as I could\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/10/05/\"\u003eAttended the Great American Beer Festival for the first time\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/10/27/\"\u003eTasted some bourbon\u003c/a\u003e in \u003ca href=\"https://thisisreal.net/2019/10/28/\"\u003eKentucky\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/10/31/\"\u003eVisited family in Ohio\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/07/\"\u003eGot a new lens\u003c/a\u003e for the \u003ca href=\"https://thisisreal.net/2019/12/28/\"\u003evenerable seeing machine\u003c/a\u003e\n\n\u003cul\u003e\n\u003cli\u003eCaptured some \u003ca href=\"https://thisisreal.net/2019/01/20/\"\u003ereflection\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2019/09/14/\"\u003eselfies\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2019/12/19/\"\u003eSaw the latest Star Wars movie\u003c/a\u003e at \u003ca href=\"https://thisisreal.net/2019/12/22/\"\u003eleast twice\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eI tend to have trouble giving myself credit for the things that I do. I am truly surprised about what I managed to accomplish this year. But it is also clear that my life was out of balance. I intend to rebalance in the future.\u003c/p\u003e\n\n\u003cp\u003eI am disappointed in myself, though, for not taking stock of 2019 sooner. I made several realizations while writing this post that I wish I had made earlier. Realizations that would have affected decisions I made during 2020, now all but spent. I\u0026rsquo;m setting a goal for myself to process all my 2020 photos and write a post for 2020 by February 2021. Wish me luck.\u003c/p\u003e\n\n\u003cp\u003eFinally, 2019 was my tenth year of attempting to capture and process at least one photo every day. I have some things to say about this and they merit a separate post that I will write some time in the future. Suffice it to say, though, that I am pleased to have this 10-year-long record of my life despite how much effort is required to create it. Perhaps my photography not quite as good as it should be given I\u0026rsquo;ve been practicing for 10 years. But looking through all my 2019 photos I\u0026rsquo;m pleased with their quality.\u003c/p\u003e\n\n\u003cp\u003eOn to 2020.\u003c/p\u003e\n",
                "content_text": "Another year, another year-end-review, I always say. Thankful to have an opportunity to reflect on another trip around the sun. You may think it\u0026rsquo;s odd to write a review of 2019 in December of 2020, but if y\u0026rsquo;all have 2020ed at all, you understand how remembering 2019 could be therapeutic.\nIf you asked me, my friends, my family, or anyone adjacent to my life, you\u0026rsquo;d know that the main theme of my 2019 was work. My day job has been as intense as ever. We\u0026rsquo;re a small company and being a small company comes with growing pains. But we have accomplished so much more than you\u0026rsquo;d expect for a 3-4 person engineering team.\n We built, tested, and deployed three (!) sensor packages. These sensor packages imaged thousands of acres at a ridiculously high resolution. Hardware is hard. Remotely debugging hardware is hard. I learned so much. I automated the GNSS post-processing workflow because I didn\u0026rsquo;t know any better. It took a huge amount of work, but the workflow is finally relatively stable and robust. I, again, did tons of sysadmin and IT work. Tons of it. I got to work on a grant awarded by a prestigious government agency.  While going through my 2019 work journal, I realized how little work I did that relates to my official title (and my career goals) and I\u0026rsquo;m frustrated about that. Even so, I encountered challenges and solved them because they needed to be solved. The passing of time has revealed just how difficult some of those challenges actually were. Many days I completed a legitimately absurd number of tasks. Often, I would go on to put in a couple hours for my second job as well. I did, however, manage to get set up to work from home—this has turned out to be important.\nThe majority of my spare time was spent on my side hustle with the goals of attending ICASSP 2020 in Barcelona and trying to grow the old savings account as much as possible. In the process, and with help from my esteemed colleague, I built an accurate no-reference speech quality estimator—a thing that\u0026rsquo;s been sort of a holy grail in the speech processing field for decades. If you asked me whether or not this was possible even 5 years ago, I would have said, \u0026ldquo;no\u0026rdquo;. In our second iteration reduced the number of parameters in the model by \u0026gt;99% and improved robustness. We wrote and submitted two papers, and the second ended up being accepted to ICASSP 2020 (mission accomplished!). I am proud of this, full stop. I am proud I was able to accomplish this in my spare time.\nEven though I spent so much time working, I really think I managed to wring everything I possibly could have out of 2019. When I wasn\u0026rsquo;t working, I:\n Started editing my photos on an iPad Spent quality time on the mountain  Ate amazing food, tolerated the dog, stared at the clouds Saw the first signs of Spring Had hammock and burrito time Got socked in Basked in the green Smelled the waldflaurs Ogled the clouds Enjoyed the snow  Got some workouts in until my gym closed 😪 Saw Antonio Sanchez (and co.) perform at the Boulder Theater Went on a few hikes  Palisade Mountain Storm Mountain Got soaked on Crosier Mountain Ouray Telluride Utah  Spent time with friends  Went to Chicago to visit Steven and Jeena Hiked around Crosier mountain A going away party for Mark Dylan\u0026rsquo;s birthday party Drinks with Dustin and Carly Brunch with the Denver crew Bike rides around Boulder with Brian  Spent time with family  Went to Steamboat with my Dad a few times Celebrated the 4th of July Mountain time with Christina\u0026rsquo;s mom Built a retaining wall Went to Utah to see my sister and brother-in-law for Thanksgiving Home to Cheyenne for Christmas  Watched Christina give a talk about her work Went to eyeo for the second time—extreme spiritual refreshment Managed to write four blog posts Printed out all my 2018 averages Ate some amazing food, drank delicous drinks  At Mateo (mmm, fries) Many delicious meals made by Christina, but specifically these biscuits and gravy Pizza at Backcountry Work meeting with Charles at Burn\u0026rsquo;s Pub  Documented some construction and change in Boulder Attended at least 20 meetups  Work in Progress Denver Creative Tech B.E.A.T. Analyze Boulder Boulder Python Ignite Boulder  Gave a talk about Docker at Boulder Python—(I am looking through this talk again and cracking myself up) Got a new Nintendo Attended my favorite lecture series, Mixed Taste Traveled to Ouray, Telluride, Grand Junction, and Palisade and got some good eating, drinking, and mountain biking in Saw the Clark Richert exhibits as many times as I could Attended the Great American Beer Festival for the first time Tasted some bourbon in Kentucky Visited family in Ohio Got a new lens for the venerable seeing machine  Captured some reflection selfies  Saw the latest Star Wars movie at least twice  I tend to have trouble giving myself credit for the things that I do. I am truly surprised about what I managed to accomplish this year. But it is also clear that my life was out of balance. I intend to rebalance in the future.\nI am disappointed in myself, though, for not taking stock of 2019 sooner. I made several realizations while writing this post that I wish I had made earlier. Realizations that would have affected decisions I made during 2020, now all but spent. I\u0026rsquo;m setting a goal for myself to process all my 2020 photos and write a post for 2020 by February 2021. Wish me luck.\nFinally, 2019 was my tenth year of attempting to capture and process at least one photo every day. I have some things to say about this and they merit a separate post that I will write some time in the future. Suffice it to say, though, that I am pleased to have this 10-year-long record of my life despite how much effort is required to create it. Perhaps my photography not quite as good as it should be given I\u0026rsquo;ve been practicing for 10 years. But looking through all my 2019 photos I\u0026rsquo;m pleased with their quality.\nOn to 2020.\n",
                "date_published": "2020-12-13T20:10:25-07:00"
            }
            , {
                "title": "What is it that you do here.",
                "id": "https://negativesign.com/blog/2020/05/06/what-is-it-that-you-do-here./",
                "url": "https://negativesign.com/blog/2020/05/06/what-is-it-that-you-do-here./",
                "summary": "I don’t usually talk about the work I do (in my free time, 😅) but If you wanna nerd out for a bit, here are some of MY OWN THOUGHTS about some PUBLICLY-AVAILABLE RESEARCH that…just happens to have my name on it.\nThe specific topic area is speech quality measurement. What does that mean? Well, you’re probably familiar with the following statements:\n “[voice service provider] sux0rz/always sounds good.”",
                
                "content_html": "\n\n\u003cp\u003eI don’t usually talk about the work I do (in my free time, 😅) but If you wanna nerd out for a bit, here are some of MY OWN THOUGHTS about some PUBLICLY-AVAILABLE RESEARCH that…just happens to have my name on it.\u003c/p\u003e\n\n\u003cp\u003eThe specific topic area is speech quality measurement. What does that mean? Well, you’re probably familiar with the following statements:\u003c/p\u003e\n\n\u003cblockquote\u003e\n\u003cp\u003e“[voice service provider] sux0rz/always sounds good.”\u003c/p\u003e\n\n\u003cp\u003e“[telephone company] never/always has good service.”\u003c/p\u003e\n\n\u003cp\u003e“My [smartphone device] drops calls here.”\u003c/p\u003e\n\n\u003cp\u003e“This building has better/worse service over here.”\u003c/p\u003e\n\u003c/blockquote\u003e\n\n\u003cp\u003eYou’ve said these things, I’ve said these things, we all scream for [reliable voice communication “system”].\u003c/p\u003e\n\n\u003cp\u003eSpeech quality measurement is the practice of quantifying how you perceive the quality of sound that’s produced by a communication device/service when it enters your earhole.\u003c/p\u003e\n\n\u003cp\u003eThink about the last phone call or video conference you had. Was there a time where you couldn’t understand the other person? A time when it sounded like the other person was talking into a Pringle’s tube lined with dirty socks? How did you feel about that? How did you, a human, take all the annoyances, missed words, robot noises, muffled sentences, and background noise and convert it into an overall opinion? Turns out there’s an enormous body of research dedicated to measuring and predicting your opinion when those things happen.\u003c/p\u003e\n\n\u003cp\u003eThe people interested in predicting your opinion can count dropped calls, measure a radio receiver’s signal-to-nose ratio (SNR), and log bandwidth usage. Some measurements have predictable impacts on what you think about [product] or even [location]. Nobody enjoys dropped calls, but I’m guessing you don’t know what SNR your phone’s radio managed for your last 5 phone calls. How low must that SNR be for you to give up on a call? In many cases SNR constrains the available network bandwidth to a certain bit rate. But do you know the bit rate threshold that causes you to hang up and try to get a better connection?\u003c/p\u003e\n\n\u003cp\u003eIt’s true that people can learn or predict relationships between these physical/software metrics and audio quality, but linking them to human behavior or opinion is Tricky. Because each human is Different. And human behavior is not Deterministic. Remember the two D’s of humans. Er, DnD. Different and non-Deterministic, DanD. Humans are DanD, I always say. At some point, though, humans will vote with their wallet (and/or attention 😢) and stop using a service that sux0rz. If [service provider] wants to stay in business, [service provider] needs to understand if their “system” does indeed sux0rz.\u003c/p\u003e\n\n\u003ch3 id=\"human-based-measurement-techniques\"\u003eHuman-Based Measurement Techniques\u003c/h3\u003e\n\n\u003cp\u003eIn order to figure that out, people can, and do, ask you for your opinion on the quality of [simulated voice call]. They ask, in a strictly controlled laboratory environment, how would you rate the quality of [simulated voice call] on a scale of 1-5? They pose this question to dozens or hundreds of people and they can come up with a good estimate of how most people will react to [simulated voice call].\u003c/p\u003e\n\n\u003cp\u003eStrictly controlled environments are expensive and so is getting you to come to them. Besides that, you make phone calls on the streets, in your car, at the clurb, and on the john. Lab tests are informative, but not representative. So some people will ask for your opinion in a “real-world” situation, like right after you call your therapist. Maybe you’ll answer, and maybe you won’t. But if they can gather enough opinions, they can overcome the lack of control and learn something about how well their “system” is performing. This approach is less expensive than a lab test, but it has lots of caveats. Your opinion can be affected by things other than the aural quality of the call, such as your therapist’s unhealthy interest in your naked math test dreams. It is possible to understand and handle these caveats, but doing so adds cost and uncertainty.\u003c/p\u003e\n\n\u003ch3 id=\"computer-based-measurement-techniques\"\u003eComputer-Based Measurement Techniques\u003c/h3\u003e\n\n\u003cp\u003eMaybe by now you’re asking if we can teach computers to predict your opinion of a call. Well, yes. Yes we can. There are many approaches to accomplish this and here are three:\u003c/p\u003e\n\n\u003col\u003e\n\u003cli\u003eAnalyzing Metadata: making predictions from call and “system” metadata\u003c/li\u003e\n\u003cli\u003eComparing to Reference: analyzing the audio put into the “system” and comparing it to the audio output from the “system”\u003c/li\u003e\n\u003cli\u003eOutput Analysis: analyzing solely the output from the “system” that goes into your earhole.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eOver the years, people have had success with the first two approaches but each have caveats. The third has been a sort of holy grail—at least until the last few years.\u003c/p\u003e\n\n\u003ch4 id=\"analyzing-metadata\"\u003eAnalyzing Metadata\u003c/h4\u003e\n\n\u003cp\u003eUsing call metadata (SNR, bit rate, call length, or other parameters) is powerful but the “system” is complicated—in some cases it’s comprised of two different handsets, two separate radio links, two separate humans, and a network that connects them, all with their own time-varying characteristics. Metadata is not always rich enough to characterize the interactions among all these parts.\u003c/p\u003e\n\n\u003ch4 id=\"comparing-to-reference\"\u003eComparing to Reference\u003c/h4\u003e\n\n\u003cp\u003eComparing the output audio to the input audio has significant advantages compared to a metadata-only approach. One advantage has more to do with \u003ca href=\"https://en.wikipedia.org/wiki/Claude_Shannon\"\u003eClaude Shannon\u003c/a\u003e than you’re comfortable with and another is that this approach fully captures the dynamics of the “system”. But [voice service provider] doesn’t have access to the unfettered input! They are not following you on the streets, riding shotgun in your car, clinging to your face at the clurb, or recording your poops. By the time [voice service provider] receives the “input” it has already traversed almost half of the “system.” This effectively limits use of this approach to the laboratory. Still valuable! Until recently, this has been the most accurate approach. But it’s not deployable.\u003c/p\u003e\n\n\u003ch4 id=\"output-analysis\"\u003eOutput Analysis\u003c/h4\u003e\n\n\u003cp\u003eThis method is essentially how humans form opinions of distorted audio. You have an idea about what it sounds like when Bob from work is standing next to you and droning on about his exploits during college: it sounds good, despite the content. You also know know what it sounds like when he’s calling you from a crowded underground grotto: bad. But how do you tell a computer how human speech should or shouldn’t sound? It’s haaaaaarrrrrrd!\u003c/p\u003e\n\n\u003cp\u003eIf we could do that though, this approach could theoretically be deployed anywhere in the “system”. The ability to know, for example, that your opinion of the audio is high until it arrives at the cell tower down the road is a great debugging tool. It could be very helpful for [service provider] to pinpoint problem areas in the “system.”\u003c/p\u003e\n\n\u003cp\u003eSo is it possible to convey that information to a computer? Well, a colleague and I have been working on this for a while, and we came up with \u003ca href=\"https://www.its.bldrdoc.gov/publications/details.aspx?pub=3242\"\u003eone method\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eThis particular method is…pretty, pretty good. It’s been tested on tons of data: our dataset includes 13 languages, 1,230 talkers, and contains more than 330 hours of speech after augmentation. Our model performs well: predictions correlate with truth data very well (r \u0026gt; 0.91), root-mean-squared errors (RMSE) are around 9% of the target value scale. Our model contains a relatively small number of parameters. Depending on how you train it the model can predict quality or intelligibility. Or some other thing! As long as you have the data. Not gonna lie—it’s one of, if not \u003cem\u003ethe\u003c/em\u003e best out there right now.\u003c/p\u003e\n\n\u003cp\u003eThis method doesn’t understand anything about the words present in a given audio signal. Or who is saying it, or what language they’re speaking. The very properties that make this method robust to widely-varied input also just happen to not undermine your privacy.\u003c/p\u003e\n\n\u003cp\u003eAll that said, I’m proud that the \u003ca href=\"https://github.com/NTIA/WEnets\"\u003ereference implementation is available\u003c/a\u003e for free. The reference implementation includes four pre-trained models. Anybody can use it—the rising tide lifts your mom or whatever. The work was published at ICASSP 2020, and at time of publishing, it\u0026rsquo;s still possible to \u003ca href=\"https://l.feathr.co/ICASSP-2020_Andrew-Catellier\"\u003eregister and watch the talk\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eAnyway, just a little about what I, MYSELF, ONE HUMAN PERSON, REPRESENTING HIS OWN SELF AND DEFINITELY NOT ANY GOVERNMENT ENTITIES IN THIS POST have been thinking IN EXTREMELY VAGUE TERMS about lately.\u003c/p\u003e\n",
                "content_text": " I don’t usually talk about the work I do (in my free time, 😅) but If you wanna nerd out for a bit, here are some of MY OWN THOUGHTS about some PUBLICLY-AVAILABLE RESEARCH that…just happens to have my name on it.\nThe specific topic area is speech quality measurement. What does that mean? Well, you’re probably familiar with the following statements:\n “[voice service provider] sux0rz/always sounds good.”\n“[telephone company] never/always has good service.”\n“My [smartphone device] drops calls here.”\n“This building has better/worse service over here.”\n You’ve said these things, I’ve said these things, we all scream for [reliable voice communication “system”].\nSpeech quality measurement is the practice of quantifying how you perceive the quality of sound that’s produced by a communication device/service when it enters your earhole.\nThink about the last phone call or video conference you had. Was there a time where you couldn’t understand the other person? A time when it sounded like the other person was talking into a Pringle’s tube lined with dirty socks? How did you feel about that? How did you, a human, take all the annoyances, missed words, robot noises, muffled sentences, and background noise and convert it into an overall opinion? Turns out there’s an enormous body of research dedicated to measuring and predicting your opinion when those things happen.\nThe people interested in predicting your opinion can count dropped calls, measure a radio receiver’s signal-to-nose ratio (SNR), and log bandwidth usage. Some measurements have predictable impacts on what you think about [product] or even [location]. Nobody enjoys dropped calls, but I’m guessing you don’t know what SNR your phone’s radio managed for your last 5 phone calls. How low must that SNR be for you to give up on a call? In many cases SNR constrains the available network bandwidth to a certain bit rate. But do you know the bit rate threshold that causes you to hang up and try to get a better connection?\nIt’s true that people can learn or predict relationships between these physical/software metrics and audio quality, but linking them to human behavior or opinion is Tricky. Because each human is Different. And human behavior is not Deterministic. Remember the two D’s of humans. Er, DnD. Different and non-Deterministic, DanD. Humans are DanD, I always say. At some point, though, humans will vote with their wallet (and/or attention 😢) and stop using a service that sux0rz. If [service provider] wants to stay in business, [service provider] needs to understand if their “system” does indeed sux0rz.\nHuman-Based Measurement Techniques In order to figure that out, people can, and do, ask you for your opinion on the quality of [simulated voice call]. They ask, in a strictly controlled laboratory environment, how would you rate the quality of [simulated voice call] on a scale of 1-5? They pose this question to dozens or hundreds of people and they can come up with a good estimate of how most people will react to [simulated voice call].\nStrictly controlled environments are expensive and so is getting you to come to them. Besides that, you make phone calls on the streets, in your car, at the clurb, and on the john. Lab tests are informative, but not representative. So some people will ask for your opinion in a “real-world” situation, like right after you call your therapist. Maybe you’ll answer, and maybe you won’t. But if they can gather enough opinions, they can overcome the lack of control and learn something about how well their “system” is performing. This approach is less expensive than a lab test, but it has lots of caveats. Your opinion can be affected by things other than the aural quality of the call, such as your therapist’s unhealthy interest in your naked math test dreams. It is possible to understand and handle these caveats, but doing so adds cost and uncertainty.\nComputer-Based Measurement Techniques Maybe by now you’re asking if we can teach computers to predict your opinion of a call. Well, yes. Yes we can. There are many approaches to accomplish this and here are three:\n Analyzing Metadata: making predictions from call and “system” metadata Comparing to Reference: analyzing the audio put into the “system” and comparing it to the audio output from the “system” Output Analysis: analyzing solely the output from the “system” that goes into your earhole.  Over the years, people have had success with the first two approaches but each have caveats. The third has been a sort of holy grail—at least until the last few years.\nAnalyzing Metadata Using call metadata (SNR, bit rate, call length, or other parameters) is powerful but the “system” is complicated—in some cases it’s comprised of two different handsets, two separate radio links, two separate humans, and a network that connects them, all with their own time-varying characteristics. Metadata is not always rich enough to characterize the interactions among all these parts.\nComparing to Reference Comparing the output audio to the input audio has significant advantages compared to a metadata-only approach. One advantage has more to do with Claude Shannon than you’re comfortable with and another is that this approach fully captures the dynamics of the “system”. But [voice service provider] doesn’t have access to the unfettered input! They are not following you on the streets, riding shotgun in your car, clinging to your face at the clurb, or recording your poops. By the time [voice service provider] receives the “input” it has already traversed almost half of the “system.” This effectively limits use of this approach to the laboratory. Still valuable! Until recently, this has been the most accurate approach. But it’s not deployable.\nOutput Analysis This method is essentially how humans form opinions of distorted audio. You have an idea about what it sounds like when Bob from work is standing next to you and droning on about his exploits during college: it sounds good, despite the content. You also know know what it sounds like when he’s calling you from a crowded underground grotto: bad. But how do you tell a computer how human speech should or shouldn’t sound? It’s haaaaaarrrrrrd!\nIf we could do that though, this approach could theoretically be deployed anywhere in the “system”. The ability to know, for example, that your opinion of the audio is high until it arrives at the cell tower down the road is a great debugging tool. It could be very helpful for [service provider] to pinpoint problem areas in the “system.”\nSo is it possible to convey that information to a computer? Well, a colleague and I have been working on this for a while, and we came up with one method.\nThis particular method is…pretty, pretty good. It’s been tested on tons of data: our dataset includes 13 languages, 1,230 talkers, and contains more than 330 hours of speech after augmentation. Our model performs well: predictions correlate with truth data very well (r \u0026gt; 0.91), root-mean-squared errors (RMSE) are around 9% of the target value scale. Our model contains a relatively small number of parameters. Depending on how you train it the model can predict quality or intelligibility. Or some other thing! As long as you have the data. Not gonna lie—it’s one of, if not the best out there right now.\nThis method doesn’t understand anything about the words present in a given audio signal. Or who is saying it, or what language they’re speaking. The very properties that make this method robust to widely-varied input also just happen to not undermine your privacy.\nAll that said, I’m proud that the reference implementation is available for free. The reference implementation includes four pre-trained models. Anybody can use it—the rising tide lifts your mom or whatever. The work was published at ICASSP 2020, and at time of publishing, it\u0026rsquo;s still possible to register and watch the talk.\nAnyway, just a little about what I, MYSELF, ONE HUMAN PERSON, REPRESENTING HIS OWN SELF AND DEFINITELY NOT ANY GOVERNMENT ENTITIES IN THIS POST have been thinking IN EXTREMELY VAGUE TERMS about lately.\n",
                "date_published": "2020-05-06T22:20:44-06:00"
            }
            , {
                "title": "Adjusting External Monitor Brightness on Your Mac",
                "id": "https://negativesign.com/blog/2020/04/18/adjusting-external-monitor-brightness-on-your-mac/",
                "url": "https://negativesign.com/blog/2020/04/18/adjusting-external-monitor-brightness-on-your-mac/",
                "summary": "I\u0026rsquo;ve been lucky to be able to work from home during this…crisis…and I\u0026rsquo;ve been using 15\u0026rdquo; MacBook Pro and a Dell 4K monitor for a second screen. It\u0026rsquo;s a nice setup—again, I\u0026rsquo;m really lucky and thankful—all the extra screen real estate is so nice for writing code and viewing images in QGIS all at the same time.\nOne thing that was less than optimal was changing the brightness of the Dell monitor throughout the day.",
                
                "content_html": "\u003cp\u003eI\u0026rsquo;ve been lucky to be able to work from home during this…crisis…and I\u0026rsquo;ve been using 15\u0026rdquo; MacBook Pro and a Dell 4K monitor for a second screen. It\u0026rsquo;s a nice setup—again, I\u0026rsquo;m really lucky and thankful—all the extra screen real estate is so nice for writing code and viewing images in QGIS all at the same time.\u003c/p\u003e\n\n\u003cp\u003eOne thing that was less than optimal was changing the brightness of the Dell monitor throughout the day. The OSD menu is actually implemented quite well but it\u0026rsquo;s still clunky compared to changing the brightness on my laptop\u0026rsquo;s built-in display.\u003c/p\u003e\n\n\u003cp\u003eEnter \u003ca href=\"https://github.com/the0neyouseek/MonitorControl\"\u003eMonitor Control\u003c/a\u003e (hat tip \u003ca href=\"https://twitter.com/reidab\"\u003eReid Beels\u003c/a\u003e). This is such a great utility. After you launch it, pushing the monitor brightness buttons on your keyboard automatically adjusts the brightness of the monitor that\u0026rsquo;s displaying the active application.\u003c/p\u003e\n\n\u003cp\u003eHighly recommended if you\u0026rsquo;ve got a non-Apple display connected to your Mac. Thanks much to all the developers.\u003c/p\u003e\n",
                "content_text": "I\u0026rsquo;ve been lucky to be able to work from home during this…crisis…and I\u0026rsquo;ve been using 15\u0026rdquo; MacBook Pro and a Dell 4K monitor for a second screen. It\u0026rsquo;s a nice setup—again, I\u0026rsquo;m really lucky and thankful—all the extra screen real estate is so nice for writing code and viewing images in QGIS all at the same time.\nOne thing that was less than optimal was changing the brightness of the Dell monitor throughout the day. The OSD menu is actually implemented quite well but it\u0026rsquo;s still clunky compared to changing the brightness on my laptop\u0026rsquo;s built-in display.\nEnter Monitor Control (hat tip Reid Beels). This is such a great utility. After you launch it, pushing the monitor brightness buttons on your keyboard automatically adjusts the brightness of the monitor that\u0026rsquo;s displaying the active application.\nHighly recommended if you\u0026rsquo;ve got a non-Apple display connected to your Mac. Thanks much to all the developers.\n",
                "date_published": "2020-04-18T18:37:45-06:00"
            }
            , {
                "title": "Navigating the Photo Metadata Wasteland",
                "id": "https://negativesign.com/blog/2020/03/31/navigating-the-photo-metadata-wasteland/",
                "url": "https://negativesign.com/blog/2020/03/31/navigating-the-photo-metadata-wasteland/",
                "summary": "I\u0026rsquo;ve been rewriting my multiple exposure software (again—the code was totally unmaintainable and totally horrible). I decided to switch from exiv2 to the excellent exiftool and pyexiftool for reading and writing image metadata. exiv2 is good! But exiftool is compatible with raw images from more camera systems.\nI didn\u0026rsquo;t have any tests so I failed to maintain the functionality of my old metadata writing tool. I couldn\u0026rsquo;t figure out why neither Lightroom nor Flickr could read the \u0026ldquo;Capture Time\u0026rdquo; I was attempting to set in metadata.",
                
                "content_html": "\u003cp\u003eI\u0026rsquo;ve been rewriting my \u003ca href=\"https://github.com/whltexbread/photomanip\"\u003emultiple exposure software\u003c/a\u003e (\u003ca href=\"https://negativesign.com/blog/2018/01/03/building-avg-day-again/\"\u003eagain\u003c/a\u003e—the code was totally unmaintainable and totally horrible). I decided to switch from \u003ca href=\"https://www.exiv2.org\"\u003e\u003ccode\u003eexiv2\u003c/code\u003e\u003c/a\u003e to the excellent \u003ca href=\"https://exiftool.org\"\u003e\u003ccode\u003eexiftool\u003c/code\u003e\u003c/a\u003e and \u003ca href=\"https://github.com/smarnach/pyexiftool\"\u003e\u003ccode\u003epyexiftool\u003c/code\u003e\u003c/a\u003e for reading and writing image metadata. \u003ccode\u003eexiv2\u003c/code\u003e is good! But \u003ccode\u003eexiftool\u003c/code\u003e is compatible with raw images from more camera systems.\u003c/p\u003e\n\n\u003cp\u003eI didn\u0026rsquo;t have any tests so I failed to maintain the functionality of my old metadata writing tool. I couldn\u0026rsquo;t figure out why neither Lightroom nor Flickr could read the \u0026ldquo;Capture Time\u0026rdquo; I was attempting to set in metadata. I searched around and found this \u003ca href=\"https://exiftool.org/forum/index.php?topic=6959.0\"\u003eforum post\u003c/a\u003e where I learned that Lightroom writes one EXIF tag, two IPTC tags, and one XMP tag that all include the \u0026ldquo;Capture Time\u0026rdquo; metadata.\u003c/p\u003e\n\n\u003cp\u003eLet\u0026rsquo;s unpack that just a tiny bit: there are three different metadata standards and one of them splits the date and the time into two separate items. Why!\u003c/p\u003e\n\n\u003cp\u003e🤬\u003c/p\u003e\n\n\u003cp\u003eThe one Flickr pays attention to is \u003ccode\u003eEXIF:DateTimeOriginal\u003c/code\u003e. I had been writing \u003ccode\u003eComposite:DateTimeCreated\u003c/code\u003e, which apparently means something to \u003ccode\u003eexiv2\u003c/code\u003e but nothing to \u003ccode\u003eexiftool\u003c/code\u003e. Maybe the \u003ccode\u003eexiv2\u003c/code\u003e method writes all four tags like Lightroom but I\u0026rsquo;m too lazy to check.\u003c/p\u003e\n\n\u003cp\u003eI also had some trouble making newlines in captions—ultimately because of how \u003ccode\u003epyexiftool\u003c/code\u003e wraps the \u003ccode\u003eexiftool\u003c/code\u003e CLI and how the \u003ccode\u003eexiftool\u003c/code\u003e \u003ca href=\"https://exiftool.org/forum/index.php?topic=1649.0\"\u003eCLI uses line feeds\u003c/a\u003e—but it is possible if you use a carriage return instead of a line feed.\u003c/p\u003e\n\n\u003cp\u003eIf \u003ca href=\"https://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/\"\u003eEXIF orientation handling is a ghetto\u003c/a\u003e, it\u0026rsquo;s a small part of the tri-standard urban wasteland that is photo metadata. Documentation is sparse and hard to come by, but thankfully the \u003ccode\u003eexiftool\u003c/code\u003e forum has been an oasis.\u003c/p\u003e\n",
                "content_text": "I\u0026rsquo;ve been rewriting my multiple exposure software (again—the code was totally unmaintainable and totally horrible). I decided to switch from exiv2 to the excellent exiftool and pyexiftool for reading and writing image metadata. exiv2 is good! But exiftool is compatible with raw images from more camera systems.\nI didn\u0026rsquo;t have any tests so I failed to maintain the functionality of my old metadata writing tool. I couldn\u0026rsquo;t figure out why neither Lightroom nor Flickr could read the \u0026ldquo;Capture Time\u0026rdquo; I was attempting to set in metadata. I searched around and found this forum post where I learned that Lightroom writes one EXIF tag, two IPTC tags, and one XMP tag that all include the \u0026ldquo;Capture Time\u0026rdquo; metadata.\nLet\u0026rsquo;s unpack that just a tiny bit: there are three different metadata standards and one of them splits the date and the time into two separate items. Why!\n🤬\nThe one Flickr pays attention to is EXIF:DateTimeOriginal. I had been writing Composite:DateTimeCreated, which apparently means something to exiv2 but nothing to exiftool. Maybe the exiv2 method writes all four tags like Lightroom but I\u0026rsquo;m too lazy to check.\nI also had some trouble making newlines in captions—ultimately because of how pyexiftool wraps the exiftool CLI and how the exiftool CLI uses line feeds—but it is possible if you use a carriage return instead of a line feed.\nIf EXIF orientation handling is a ghetto, it\u0026rsquo;s a small part of the tri-standard urban wasteland that is photo metadata. Documentation is sparse and hard to come by, but thankfully the exiftool forum has been an oasis.\n",
                "date_published": "2020-03-31T07:53:47-06:00"
            }
            , {
                "title": "Use GRUB to Boot From Ubuntu Into a Different OS",
                "id": "https://negativesign.com/blog/2019/03/14/use-grub-to-boot-from-ubuntu-into-a-different-os/",
                "url": "https://negativesign.com/blog/2019/03/14/use-grub-to-boot-from-ubuntu-into-a-different-os/",
                "summary": "Yesterday I was working from home and needed to boot my Ubuntu-based office computer into Windows. I really didn’t want to brave the bomb cyclone (again) so I did some quick searching to see if I could do this remotely—without manually interacting with the EFI boot screen.\nSurely you should be able to tell GRUB which OS to start on next boot, right? Right. Here’s how.\nFirst, use this one-liner to get the name of the GRUB menu item you want to run on next boot:",
                
                "content_html": "\u003cp\u003eYesterday I was working from home and needed to boot my Ubuntu-based office computer into Windows. I really didn’t want to brave the \u003ca href=\"https://www.washingtonpost.com/weather/2019/03/14/bomb-cyclone-bolts-toward-upper-midwest-after-blasting-colorado-plains/\"\u003ebomb cyclone\u003c/a\u003e (again) so I did some quick \u003ca href=\"https://DuckDuckGo.com\"\u003esearching\u003c/a\u003e to see if I could do this remotely—without manually interacting with the EFI boot screen.\u003c/p\u003e\n\n\u003cp\u003eSurely you should be able to tell \u003ca href=\"https://www.gnu.org/software/grub/\"\u003eGRUB\u003c/a\u003e which OS to start on next boot, right? Right. Here’s how.\u003c/p\u003e\n\n\u003cp\u003eFirst, use \u003ca href=\"https://askubuntu.com/a/999550\"\u003ethis one-liner\u003c/a\u003e to get the name of the GRUB menu item you want to run on next boot:\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e# awk -F\\' '/^menuentry / {print $2}' /boot/grub/grub.cfg|cat -n|awk '{print $1-1,$1=\u0026quot;\u0026quot;,$0}'\n0   Ubuntu\n1   Windows Boot Manager (on /dev/nvme0n1p1)\n2   System setup\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eSince I wanted to boot into Windows, I typed:\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e # sudo grub-reboot \u0026quot;Windows Boot Manager (on /dev/nvme0n1p1)\u0026quot;\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eThen, reboot the machine.\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e# sudo reboot\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNice! The machine should now boot into Windows.\u003c/p\u003e\n\n\u003cp\u003e💪💪💪💪\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eYou \u003cem\u003eshould\u003c/em\u003e be able to just \u003ca href=\"https://askubuntu.com/a/661535\"\u003especify the number\u003c/a\u003e of the GRUB option you’d like to select, but I was having trouble with  that and couldn’t figure out why. I do know that for me, specifying both the \u003ccode\u003egrub-reboot\u003c/code\u003e and the \u003ccode\u003ereboot\u003c/code\u003e command on the same line wasn’t working.\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": "Yesterday I was working from home and needed to boot my Ubuntu-based office computer into Windows. I really didn’t want to brave the bomb cyclone (again) so I did some quick searching to see if I could do this remotely—without manually interacting with the EFI boot screen.\nSurely you should be able to tell GRUB which OS to start on next boot, right? Right. Here’s how.\nFirst, use this one-liner to get the name of the GRUB menu item you want to run on next boot:\n# awk -F\\' '/^menuentry / {print $2}' /boot/grub/grub.cfg|cat -n|awk '{print $1-1,$1=\u0026quot;\u0026quot;,$0}' 0 Ubuntu 1 Windows Boot Manager (on /dev/nvme0n1p1) 2 System setup  Since I wanted to boot into Windows, I typed:1\n # sudo grub-reboot \u0026quot;Windows Boot Manager (on /dev/nvme0n1p1)\u0026quot;  Then, reboot the machine.\n# sudo reboot  Nice! The machine should now boot into Windows.\n💪💪💪💪\n You should be able to just specify the number of the GRUB option you’d like to select, but I was having trouble with that and couldn’t figure out why. I do know that for me, specifying both the grub-reboot and the reboot command on the same line wasn’t working. [return]   ",
                "date_published": "2019-03-14T17:14:33-06:00"
            }
            , {
                "title": "2018 in Review",
                "id": "https://negativesign.com/blog/2019/01/13/2018-in-review/",
                "url": "https://negativesign.com/blog/2019/01/13/2018-in-review/",
                "summary": "Last year I wrote a small summary of the things I accomplished throughout 2017. I am glad I did that last year and I wanted to do it again. So. Here is another bulleted list to summarize the most recent arbitrary unit of time that I managed to traverse.\nI didn’t switch careers, there were no weddings, and I maybe worked more than I should have. But I did make a concerted effort to push my creative/not-day-job work forward, held down a side-hustle, somehow managed to go on several vacations, and put some money away for an emergency or a self-imposed sabbatical.",
                
                "content_html": "\u003cp\u003eLast year I \u003ca href=\"https://negativesign.com/blog/2017/12/31/2017-in-review/\"\u003ewrote a small summary of the things I accomplished throughout 2017\u003c/a\u003e. I am glad I did that last year and I wanted to do it again. So. Here is another bulleted list to summarize the most recent arbitrary unit of time that I managed to traverse.\u003c/p\u003e\n\n\u003cp\u003eI didn’t switch careers, there were no weddings, and I maybe worked more than I should have. But I did make a concerted effort to push my creative/not-day-job work forward, held down a side-hustle, somehow managed to go on several vacations, and put some money away for an emergency or a self-imposed sabbatical.\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eAt work I:\n\n\u003cul\u003e\n\u003cli\u003eFurther developed a GIS image processing pipeline that the company depends on as a first processing step\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/02/20/\"\u003eContributed\u003c/a\u003e to an \u003ca href=\"https://github.com/mapbox/rasterio/pull/1278\"\u003eopen source project\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/03/05/\"\u003eEvaluated imaging systems\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2018/10/29/\"\u003eeventually\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/10/30/\"\u003edesigned\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2018/11/05/\"\u003eintegrated\u003c/a\u003e a \u003ca href=\"https://thisisreal.net/2018/11/15/\"\u003ecustom\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/11/20/\"\u003esystem\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eContainerized our processing pipeline/environment\u003c/li\u003e\n\u003cli\u003eDeveloped tons of internal tools and even a couple products\u003c/li\u003e\n\u003cli\u003eMore sysadmin and IT work than I’d care to admit\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eOn top of my main job, I managed to maintain a \u003ca href=\"https://thisisreal.net/2018/11/10/\"\u003eside hustle doing deep learning\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eTook so many photos, which resulted in \u003ca href=\"https://thisisreal.net/2018/\"\u003e333 dailies\u003c/a\u003e, the most so far\u003c/li\u003e\n\u003cli\u003eMet a former band member of \u003ca href=\"https://thisisreal.net/2018/01/24/\"\u003eThe Rolling Stones because Christina is a Big Deal\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/03/25/\"\u003eBought a brand new seeing machine\u003c/a\u003e (after \u003ca href=\"https://thisisreal.net/2018/01/31\"\u003ealmost buying an even more extravagant one\u003c/a\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/02/09\"\u003eAte\u003c/a\u003e so much good food. \u003ca href=\"https://thisisreal.net/2018/02/06\"\u003eChristina\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/03/18\"\u003eis extremely\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/04/21\"\u003etalented\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2018/07/07/\"\u003ecreative\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/07/30/\"\u003ein the kitchen\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2018/12/29/\"\u003eI am so\u003c/a\u003e, \u003ca href=\"https://thisisreal.net/2018/08/04/\"\u003eso lucky\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/08/11/\"\u003ethat she enjoys\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/08/20/\"\u003emaking\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/10/22/\"\u003edelicious\u003c/a\u003e \u003ca href=\"thisisreal.net/2018/12/15/\"\u003efood\u003c/a\u003e. I was also able to \u003ca href=\"https://thisisreal.net/2018/03/14\"\u003eenjoy\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/04/04\"\u003esome\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/05/17/\"\u003edelicious\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/07/21/\"\u003emeals\u003c/a\u003e in restaurants, including a \u003ca href=\"https://thisisreal.net/2018/12/06/\"\u003evisit to Frasca\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eWorked to publicize my art/non-work accomplishments:\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/02/12/\"\u003eEntered an Ello art contest\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/03/30/\"\u003eDisplayed some work at BMoCA’s open wall\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/06/07\"\u003eGave a presentation on my avgday project\u003c/a\u003e at the amazing eyeo festival\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/06/\"\u003eSubmitted a photo project\u003c/a\u003e to the Lenswork Seeing in Sixes publication\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://negativesign.com\"\u003eUpdated and redesigned my blog\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/09/20/\"\u003eGave a talk to 1000+ people\u003c/a\u003e at \u003ca href=\"https://www.youtube.com/channel/UCb3r8w2uN6byUYz19xMzyrw\"\u003eIgnite Boulder\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eSubmitted several talk proposals to the Boulder Python meetup and \u003ca href=\"https://thisisreal.net/2018/10/09/\"\u003egave one\u003c/a\u003e \u003ca href=\"https://thisisreal.net/talks/20181009_boulder_python/#/\"\u003eof them\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eStill managed to get away from the grind:\n\n\u003cul\u003e\n\u003cli\u003eWent to \u003ca href=\"https://thisisreal.net/2018/04/02/\"\u003ePortland\u003c/a\u003e and \u003ca href=\"https://thisisreal.net/2018/04/06/\"\u003eSeattle\u003c/a\u003e to enjoy the food and be tourists\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/06/04/\"\u003eTraveled to Minneapolis to attend the eyeo conference\u003c/a\u003e for the first time—my new favorite conference—\u003ca href=\"https://thisisreal.net/2018/06/05/\"\u003ewhere I met Teju Cole\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/09/06/\"\u003ePortland (again!) for xoxo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eFirst occasion to spend time in Montana—\u003ca href=\"https://thisisreal.net/2018/09/28/\"\u003eWhitefish and Glacier National Park\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eManaged to get pictures of airplane shadows on \u003ca href=\"https://thisisreal.net/2018/04/10/\"\u003etwo\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2018/09/10/\"\u003eoccasions\u003c/a\u003e (whatever I am proud of this don’t @ me)\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2018/07/11/\"\u003eMade it down to Denver\u003c/a\u003e for \u003ca href=\"https://mcadenver.org/events/series/mixed-taste-dcpa\"\u003eMixed Taste\u003c/a\u003e in the summer\u003c/li\u003e\n\u003cli\u003eSaw \u003ca href=\"https://thisisreal.net/2018/07/18/\"\u003eSylvan Esso (and see-through plastic pants) at Red Rocks\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eMostly \u003ca href=\"https://thisisreal.net/2018/08/27/\"\u003eworked through my 35th birthday\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eOnly \u003ca href=\"https://thisisreal.net/2018/09/02/\"\u003erode the mountain bike\u003c/a\u003e a couple times ☹️\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eAll in all, an incredibly eventful year. So many things happened; it went by so quickly. I know I missed some important things. But I do think it’s good for me to take stock of the year and I’m really pleased that my dailies project—having completed its ninth year—has facilitated this so well.\u003c/p\u003e\n\n\u003cp\u003eHere’s to 2019 and continuing to grow in a positive direction.\u003c/p\u003e\n",
                "content_text": "Last year I wrote a small summary of the things I accomplished throughout 2017. I am glad I did that last year and I wanted to do it again. So. Here is another bulleted list to summarize the most recent arbitrary unit of time that I managed to traverse.\nI didn’t switch careers, there were no weddings, and I maybe worked more than I should have. But I did make a concerted effort to push my creative/not-day-job work forward, held down a side-hustle, somehow managed to go on several vacations, and put some money away for an emergency or a self-imposed sabbatical.\n At work I:  Further developed a GIS image processing pipeline that the company depends on as a first processing step Contributed to an open source project Evaluated imaging systems and eventually designed and integrated a custom system Containerized our processing pipeline/environment Developed tons of internal tools and even a couple products More sysadmin and IT work than I’d care to admit  On top of my main job, I managed to maintain a side hustle doing deep learning Took so many photos, which resulted in 333 dailies, the most so far Met a former band member of The Rolling Stones because Christina is a Big Deal Bought a brand new seeing machine (after almost buying an even more extravagant one) Ate so much good food. Christina is extremely talented and creative in the kitchen and I am so, so lucky that she enjoys making delicious food. I was also able to enjoy some delicious meals in restaurants, including a visit to Frasca. Worked to publicize my art/non-work accomplishments:  Entered an Ello art contest Displayed some work at BMoCA’s open wall Gave a presentation on my avgday project at the amazing eyeo festival Submitted a photo project to the Lenswork Seeing in Sixes publication Updated and redesigned my blog Gave a talk to 1000+ people at Ignite Boulder Submitted several talk proposals to the Boulder Python meetup and gave one of them  Still managed to get away from the grind:  Went to Portland and Seattle to enjoy the food and be tourists Traveled to Minneapolis to attend the eyeo conference for the first time—my new favorite conference—where I met Teju Cole Portland (again!) for xoxo First occasion to spend time in Montana—Whitefish and Glacier National Park  Managed to get pictures of airplane shadows on two occasions (whatever I am proud of this don’t @ me) Made it down to Denver for Mixed Taste in the summer Saw Sylvan Esso (and see-through plastic pants) at Red Rocks Mostly worked through my 35th birthday Only rode the mountain bike a couple times ☹️  All in all, an incredibly eventful year. So many things happened; it went by so quickly. I know I missed some important things. But I do think it’s good for me to take stock of the year and I’m really pleased that my dailies project—having completed its ninth year—has facilitated this so well.\nHere’s to 2019 and continuing to grow in a positive direction.\n",
                "date_published": "2019-01-13T21:17:11-07:00"
            }
            , {
                "title": "Autostarting Docker Compose as Linux a Service",
                "id": "https://negativesign.com/blog/2018/11/25/autostarting-docker-compose-as-linux-a-service/",
                "url": "https://negativesign.com/blog/2018/11/25/autostarting-docker-compose-as-linux-a-service/",
                "summary": "In my previous post I talked about how to build some Docker containers to run a deep learning-focused1 JupyterHub instance.\nIt\u0026rsquo;s nice for several reasons if the JupyterHub server brings itself up when the system starts. Here\u0026rsquo;s how to do that—an adaptation of this Stack Overflow post.\nCreate a file at /etc/systemd/system/docker-jupyterhub.service and put the following text into the file.\n[Unit] Description=JupyterHub container Requires=docker.service After=docker.service [Service] Restart=always ExecStart=/usr/local/bin/docker-compose start -f /path/to/GPU-Jupyterhub/docker-compose.",
                
                "content_html": "\u003cp\u003eIn my \u003ca href=\"https://negativesign.com/blog/2018/11/11/docker-and-jupyterhub-for-deep-learning/\"\u003eprevious post\u003c/a\u003e I talked about how to build some Docker containers to run a deep learning-focused\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e JupyterHub instance.\u003c/p\u003e\n\n\u003cp\u003eIt\u0026rsquo;s nice for several reasons if the JupyterHub server brings itself up when the system starts. Here\u0026rsquo;s how to do that—an adaptation of this \u003ca href=\"https://stackoverflow.com/a/39493500/650427\"\u003eStack Overflow post\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eCreate a file at \u003ccode\u003e/etc/systemd/system/docker-jupyterhub.service\u003c/code\u003e and put the following text into the file.\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003e[Unit]\nDescription=JupyterHub container\nRequires=docker.service\nAfter=docker.service\n\n[Service]\nRestart=always\nExecStart=/usr/local/bin/docker-compose start -f /path/to/GPU-Jupyterhub/docker-compose.yml --project-directory /path/to/GPU-Jupyterhub/\nExecStop=/usr/local/bin/docker-compose stop -f /path/to/GPU-Jupyterhub/docker-compose.yml --project-directory /path/to/GPU-Jupyterhub/\n\n[Install]\nWantedBy=default.target\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eOnce that file has been created, issue the following command:\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003esudo systemctl enable docker-jupyterhub.service\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eNow the JupyterHub server should start when the host computer boots and you won\u0026rsquo;t have to login to start it manually.\u003c/p\u003e\n\n\u003cp\u003eIt was a little tricky to find that \u003ccode\u003e--project-directory\u003c/code\u003e flag, and turns out it\u0026rsquo;s important to put the \u003ccode\u003estart\u003c/code\u003e and \u003ccode\u003estop\u003c/code\u003e before any other arguments.\u003c/p\u003e\n\n\u003cp\u003e¯\u0026#92;\u0026#95;(ツ)\u0026#95;/¯\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eugh\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": "In my previous post I talked about how to build some Docker containers to run a deep learning-focused1 JupyterHub instance.\nIt\u0026rsquo;s nice for several reasons if the JupyterHub server brings itself up when the system starts. Here\u0026rsquo;s how to do that—an adaptation of this Stack Overflow post.\nCreate a file at /etc/systemd/system/docker-jupyterhub.service and put the following text into the file.\n[Unit] Description=JupyterHub container Requires=docker.service After=docker.service [Service] Restart=always ExecStart=/usr/local/bin/docker-compose start -f /path/to/GPU-Jupyterhub/docker-compose.yml --project-directory /path/to/GPU-Jupyterhub/ ExecStop=/usr/local/bin/docker-compose stop -f /path/to/GPU-Jupyterhub/docker-compose.yml --project-directory /path/to/GPU-Jupyterhub/ [Install] WantedBy=default.target  Once that file has been created, issue the following command:\nsudo systemctl enable docker-jupyterhub.service  Now the JupyterHub server should start when the host computer boots and you won\u0026rsquo;t have to login to start it manually.\nIt was a little tricky to find that --project-directory flag, and turns out it\u0026rsquo;s important to put the start and stop before any other arguments.\n¯\u0026#92;\u0026#95;(ツ)\u0026#95;/¯\n ugh [return]   ",
                "date_published": "2018-11-25T22:40:50-07:00"
            }
            , {
                "title": "Docker and JupyterHub for Deep Learning",
                "id": "https://negativesign.com/blog/2018/11/11/docker-and-jupyterhub-for-deep-learning/",
                "url": "https://negativesign.com/blog/2018/11/11/docker-and-jupyterhub-for-deep-learning/",
                "summary": "If you\u0026rsquo;ve gone down the road of building your own machine for \u0026ldquo;deep learning\u0026rdquo;,1 you may also have some sort of Jupyter Notebook server running on it. You may also be able to access that server when you\u0026rsquo;re not on your local network. The Jupyter Foundation have done a good job of documenting how to do this in a fairly secure way. But standalone Jupyter Notebook servers aren\u0026rsquo;t ideal if you want more than one person to be able to access your machine.",
                
                "content_html": "\n\n\u003cp\u003eIf you\u0026rsquo;ve gone down the road of \u003ca href=\"https://medium.com/the-mission/why-building-your-own-deep-learning-computer-is-10x-cheaper-than-aws-b1c91b55ce8c\"\u003ebuilding your own machine\u003c/a\u003e for \u0026ldquo;deep learning\u0026rdquo;,\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e you may also have some sort of \u003ca href=\"https://jupyter.org\"\u003eJupyter Notebook\u003c/a\u003e server running on it. You may also be able to access that server when you\u0026rsquo;re not on your local network. The Jupyter Foundation have done a good job of \u003ca href=\"https://jupyter-notebook.readthedocs.io/en/stable/public_server.html\"\u003edocumenting\u003c/a\u003e how to do this in a fairly secure way. But standalone Jupyter Notebook servers aren\u0026rsquo;t ideal if you want more than one person to be able to access your machine.\u003c/p\u003e\n\n\u003cp\u003eIn my case, a couple users need access to a deep learning server and I like the idea of being able to quickly deploy elsewhere if needed. I don\u0026rsquo;t really need to go full \u003ca href=\"https://zero-to-jupyterhub.readthedocs.io/en/latest/\"\u003eK8s\u003c/a\u003e, so I decided to set up a \u003ca href=\"https://jupyterhub.readthedocs.io/en/stable/\"\u003eJupyterHub\u003c/a\u003e server using Docker.\u003c/p\u003e\n\n\u003cp\u003eIn order to be able to use JupyterHub in a Docker container and access your NVIDIA GPU, there are three high-level steps to complete:\u003c/p\u003e\n\n\u003col\u003e\n\u003cli\u003e\u003ca href=\"#install-docker-and-nvidia-docker\"\u003eInstall NVIDIA display drivers and CUDA onto your system\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#install-docker-and-nvidia-docker\"\u003eInstall Docker and NVIDIA Docker\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#build-a-deep-learning-container-and-tell-jupyterhub-to-use-it\"\u003eBuild a Deep Learning Container and Tell JupyterHub to Use It\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eI\u0026rsquo;ll quickly go through the first two before addressing some pain points in the last one.\u003c/p\u003e\n\n\u003ch3 id=\"installing-display-drivers-and-cuda\"\u003eInstalling Display Drivers and CUDA\u003c/h3\u003e\n\n\u003cp\u003eMy machine is running Ubuntu 18.04, and unfortunately that means some compatibility issues with CUDA 9.2.\u003csup class=\"footnote-ref\" id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\"\u003e2\u003c/a\u003e\u003c/sup\u003e CUDA 10.0 installs just fine and it requires NVIDIA driver release \u003ccode\u003e410\u003c/code\u003e. To install the NVIDIA display drivers:\u003c/p\u003e\n\n\u003cpre\u003e\u003ccode\u003esudo add-apt-repository ppa:graphics-drivers/ppa\nsudo apt update\nsudo apt install nvidia-396\n\u003c/code\u003e\u003c/pre\u003e\n\n\u003cp\u003eWait a second, why didn\u0026rsquo;t we install \u003ccode\u003e410\u003c/code\u003e just then? Well, at time of writing, \u003ccode\u003e410\u003c/code\u003e isn\u0026rsquo;t…accessible via the command line (?!) due to some logical reason on NVIDIA\u0026rsquo;s part or my ignorance of the \u003ccode\u003eapt\u003c/code\u003e package manager. However, you can install \u003ccode\u003e410\u003c/code\u003e by loading the \u003ccode\u003eSoftware \u0026amp; Updates\u003c/code\u003e program, clicking on \u003ccode\u003eAdditional Drivers\u003c/code\u003e and then selecting the \u003ccode\u003e410\u003c/code\u003e metapackage driver.\u003c/p\u003e\n\n\u003cp\u003eAfter that, it\u0026rsquo;s easy to follow the \u003ca href=\"https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html\"\u003eCUDA Installation Guide\u003c/a\u003e. Might as well \u003ca href=\"https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html\"\u003einstall CuDNN\u003c/a\u003e while you\u0026rsquo;re at it.\u003c/p\u003e\n\n\u003ch3 id=\"install-docker-and-nvidia-docker\"\u003eInstall Docker and NVIDIA Docker\u003c/h3\u003e\n\n\u003cp\u003eThis part is straightforward. Follow the official \u003ca href=\"https://docs.docker.com/install/linux/docker-ce/ubuntu/\"\u003eDocker install directions\u003c/a\u003e and then follow the directions to \u003ca href=\"https://github.com/NVIDIA/nvidia-docker\"\u003einstall NVIDIA Docker\u003c/a\u003e. You might consider adding yourself to the \u003ccode\u003edocker\u003c/code\u003e group as well.\u003c/p\u003e\n\n\u003ch3 id=\"build-a-deep-learning-container-and-tell-jupyterhub-to-use-it\"\u003eBuild a Deep Learning Container and Tell JupyterHub to Use It\u003c/h3\u003e\n\n\u003cp\u003eHere\u0026rsquo;s where it gets complicated. At this point, we are able to access our GPU from within a Docker container (cool!). Using JupyterHub, it\u0026rsquo;s easy to specify which container you\u0026rsquo;d like it to launch when a user logs in, but that container has a few competing requirements:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eIt must have Jupyter/JupyterHub installed, and must have a suitable entrypoint in place\u003c/li\u003e\n\u003cli\u003eThe container itself must have the same version of CUDA installed as what\u0026rsquo;s on the host\u003c/li\u003e\n\u003cli\u003eThe container must also have any libraries/software you require\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eThat doesn\u0026rsquo;t sound that difficult, but it rules out cool projects like \u003ca href=\"https://github.com/ufoym/deepo\"\u003eDeepo\u003c/a\u003e and \u003ca href=\"https://github.com/pjreddie/darknet\"\u003eDarknet\u003c/a\u003e and complicates the usage of the \u003ca href=\"https://docs.nvidia.com/ngc/index.html\"\u003eNVIDIA Cloud\u003c/a\u003e containers.\u003csup class=\"footnote-ref\" id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\"\u003e3\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\n\u003cp\u003eIn the middle of trying to solve this problem, I stumbled on a project called \u003ca href=\"https://github.com/FAU-DLM/GPU-Jupyterhub\"\u003eGPU-Jupyterhub\u003c/a\u003e. It appears to be a fork of \u003ca href=\"https://github.com/jupyterhub/jupyterhub-deploy-docker\"\u003e\u003ccode\u003ejupyterhub-deploy-docker\u003c/code\u003e\u003c/a\u003e with a user container that\u0026rsquo;s been modified to inherit from the \u003ca href=\"https://hub.docker.com/r/nvidia/cuda/\"\u003eNVIDIA CUDA container images\u003c/a\u003e on Docker Hub. Basically the author of GPU-Jupyterhub\u003csup class=\"footnote-ref\" id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\"\u003e4\u003c/a\u003e\u003c/sup\u003e did the work of building a container with Jupyter/JupyterHub and lots of other goodies (Tensorflow, Tensor Board, Keras, PyTorch, others) installed.\u003c/p\u003e\n\n\u003cp\u003eGreat! I \u003ca href=\"https://github.com/whlteXbread/GPU-Jupyterhub\"\u003eforked that repository\u003c/a\u003e, removed some medical imaging libraries which I won\u0026rsquo;t use, tried to clean up dependencies, made sure user containers were spawned in the NVIDIA Docker runtime, added a place for users to access common data, and tried to make the install process a little easier. Also, due to my specific configuration, using GitHub as an authenticator is not an option, so I\u0026rsquo;m using the PAM authenticator. Here is how to set up JupyterHub:\u003c/p\u003e\n\n\u003col\u003e\n\u003cli\u003eClone my \u003ca href=\"https://github.com/whlteXbread/GPU-Jupyterhub\"\u003eGPU JupyterHub repo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/jupyterhub/jupyterhub-deploy-docker#build-the-jupyterhub-docker-image\"\u003eMake a userlist file\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eUpdate \u003ccode\u003ec.Authenticator.whitelist\u003c/code\u003e and \u003ccode\u003ec.Authenticator.admin_users\u003c/code\u003e in \u003ccode\u003ejupyterhub_config.py\u003c/code\u003e as needed\u003c/li\u003e\n\u003cli\u003eAdd desired users and passwords to \u003ccode\u003eDockerfile.jupyterhub\u003c/code\u003e, \u003ca href=\"https://github.com/whlteXbread/GPU-Jupyterhub/blob/master/Jupyterhub_image/Dockerfile.jupyterhub\"\u003eexample here\u003c/a\u003e—this is necessary to use PAM user/pass authentication\u003c/li\u003e\n\u003cli\u003eGenerate a value for \u003ccode\u003eCONFIGPROXY_AUTH_TOKEN\u003c/code\u003e and \u003ccode\u003ePOSTGRES_PASSWORD\u003c/code\u003e in the file \u003ccode\u003e.env\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eGenerate an SSL certificate (through Let\u0026rsquo;s Encrypt if you\u0026rsquo;ve got some DNS A records pointing to your deep learning machine or by \u003ca href=\"https://askubuntu.com/a/300663\"\u003esigning your own\u003c/a\u003e) and place it in a directory called \u003ccode\u003e.ssl\u003c/code\u003e at the root level of the repository\u003c/li\u003e\n\u003cli\u003eCreate Docker networks and volumes for JupyterHub—examples in \u003ccode\u003edocker-compose.yml\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eEdit the last volume in the \u003ccode\u003ehub\u003c/code\u003e service in \u003ccode\u003edocker-compose.yml\u003c/code\u003e file to point to a directory on the host with data you\u0026rsquo;d like users to share\u003c/li\u003e\n\u003cli\u003eBuild the base notebook while in the \u003ccode\u003ebase-notebook\u003c/code\u003e directory: \u003ccode\u003edocker build -t base-notebook-gpu .\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBuild the Tensorflow notebook while in the \u003ccode\u003etensorflow-notebook-gpu\u003c/code\u003e directory: \u003ccode\u003edocker build -t hub-deep-learning-notebook-gpu .\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eBuild the JupyterHub system from the root of the repo: \u003ccode\u003edocker-compose up --build\u003c/code\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eIf everything went well (hahaha) you should be able to access your JupyterHub server at \u003ccode\u003ehttps://localhost\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003eIf there\u0026rsquo;s an install step I forgot (very likely), please let me know. If you\u0026rsquo;d like to take on cleaning up that main container, you\u0026rsquo;re my hero.\u003c/p\u003e\n\n\u003cp\u003eThere are definitely lots of improvements yet to be made and I know there are some weird things happening in the Dockerfiles, in the \u003ccode\u003econda\u003c/code\u003e environment, and basic configuration. That said, this will get you up and running.\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eThat term still sounds goofy to me, but I suppose I\u0026rsquo;m just showing my age.\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003eI ended up \u003ca href=\"https://gist.github.com/whlteXbread/74b29bf90ce383b4bed15b2c526dcddd\"\u003esolving\u003c/a\u003e those issues. And then I had issues \u003ca href=\"https://askubuntu.com/a/1085964/62517\"\u003euninstalling CUDA 9.2\u003c/a\u003e but there\u0026rsquo;s no need to reopen those wounds.\n \u003ca class=\"footnote-return\" href=\"#fnref:2\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003eThe \u003ca href=\"https://docs.nvidia.com/deeplearning/dgx/pytorch-release-notes/rel_18.11.html#rel_18.11\"\u003eNVIDIA Cloud PyTorch container image\u003c/a\u003e runs CUDA 10 and has a preview of features from \u003ca href=\"https://news.developer.nvidia.com/pytorch-1-0-accelerated-on-nvidia-gpus/\"\u003ePyTorch 1.0\u003c/a\u003e. But it\u0026rsquo;s based on Ubuntu 16.04. 🤷‍♂️\n \u003ca class=\"footnote-return\" href=\"#fnref:3\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003eSamir Jabari from Friedrich-Alexander Universitat—unfortunately the blog posts associated with this repo are now returning 404.\n \u003ca class=\"footnote-return\" href=\"#fnref:4\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": " If you\u0026rsquo;ve gone down the road of building your own machine for \u0026ldquo;deep learning\u0026rdquo;,1 you may also have some sort of Jupyter Notebook server running on it. You may also be able to access that server when you\u0026rsquo;re not on your local network. The Jupyter Foundation have done a good job of documenting how to do this in a fairly secure way. But standalone Jupyter Notebook servers aren\u0026rsquo;t ideal if you want more than one person to be able to access your machine.\nIn my case, a couple users need access to a deep learning server and I like the idea of being able to quickly deploy elsewhere if needed. I don\u0026rsquo;t really need to go full K8s, so I decided to set up a JupyterHub server using Docker.\nIn order to be able to use JupyterHub in a Docker container and access your NVIDIA GPU, there are three high-level steps to complete:\n Install NVIDIA display drivers and CUDA onto your system Install Docker and NVIDIA Docker Build a Deep Learning Container and Tell JupyterHub to Use It  I\u0026rsquo;ll quickly go through the first two before addressing some pain points in the last one.\nInstalling Display Drivers and CUDA My machine is running Ubuntu 18.04, and unfortunately that means some compatibility issues with CUDA 9.2.2 CUDA 10.0 installs just fine and it requires NVIDIA driver release 410. To install the NVIDIA display drivers:\nsudo add-apt-repository ppa:graphics-drivers/ppa sudo apt update sudo apt install nvidia-396  Wait a second, why didn\u0026rsquo;t we install 410 just then? Well, at time of writing, 410 isn\u0026rsquo;t…accessible via the command line (?!) due to some logical reason on NVIDIA\u0026rsquo;s part or my ignorance of the apt package manager. However, you can install 410 by loading the Software \u0026amp; Updates program, clicking on Additional Drivers and then selecting the 410 metapackage driver.\nAfter that, it\u0026rsquo;s easy to follow the CUDA Installation Guide. Might as well install CuDNN while you\u0026rsquo;re at it.\nInstall Docker and NVIDIA Docker This part is straightforward. Follow the official Docker install directions and then follow the directions to install NVIDIA Docker. You might consider adding yourself to the docker group as well.\nBuild a Deep Learning Container and Tell JupyterHub to Use It Here\u0026rsquo;s where it gets complicated. At this point, we are able to access our GPU from within a Docker container (cool!). Using JupyterHub, it\u0026rsquo;s easy to specify which container you\u0026rsquo;d like it to launch when a user logs in, but that container has a few competing requirements:\n It must have Jupyter/JupyterHub installed, and must have a suitable entrypoint in place The container itself must have the same version of CUDA installed as what\u0026rsquo;s on the host The container must also have any libraries/software you require  That doesn\u0026rsquo;t sound that difficult, but it rules out cool projects like Deepo and Darknet and complicates the usage of the NVIDIA Cloud containers.3\nIn the middle of trying to solve this problem, I stumbled on a project called GPU-Jupyterhub. It appears to be a fork of jupyterhub-deploy-docker with a user container that\u0026rsquo;s been modified to inherit from the NVIDIA CUDA container images on Docker Hub. Basically the author of GPU-Jupyterhub4 did the work of building a container with Jupyter/JupyterHub and lots of other goodies (Tensorflow, Tensor Board, Keras, PyTorch, others) installed.\nGreat! I forked that repository, removed some medical imaging libraries which I won\u0026rsquo;t use, tried to clean up dependencies, made sure user containers were spawned in the NVIDIA Docker runtime, added a place for users to access common data, and tried to make the install process a little easier. Also, due to my specific configuration, using GitHub as an authenticator is not an option, so I\u0026rsquo;m using the PAM authenticator. Here is how to set up JupyterHub:\n Clone my GPU JupyterHub repo Make a userlist file Update c.Authenticator.whitelist and c.Authenticator.admin_users in jupyterhub_config.py as needed Add desired users and passwords to Dockerfile.jupyterhub, example here—this is necessary to use PAM user/pass authentication Generate a value for CONFIGPROXY_AUTH_TOKEN and POSTGRES_PASSWORD in the file .env Generate an SSL certificate (through Let\u0026rsquo;s Encrypt if you\u0026rsquo;ve got some DNS A records pointing to your deep learning machine or by signing your own) and place it in a directory called .ssl at the root level of the repository Create Docker networks and volumes for JupyterHub—examples in docker-compose.yml Edit the last volume in the hub service in docker-compose.yml file to point to a directory on the host with data you\u0026rsquo;d like users to share Build the base notebook while in the base-notebook directory: docker build -t base-notebook-gpu . Build the Tensorflow notebook while in the tensorflow-notebook-gpu directory: docker build -t hub-deep-learning-notebook-gpu . Build the JupyterHub system from the root of the repo: docker-compose up --build  If everything went well (hahaha) you should be able to access your JupyterHub server at https://localhost.\nIf there\u0026rsquo;s an install step I forgot (very likely), please let me know. If you\u0026rsquo;d like to take on cleaning up that main container, you\u0026rsquo;re my hero.\nThere are definitely lots of improvements yet to be made and I know there are some weird things happening in the Dockerfiles, in the conda environment, and basic configuration. That said, this will get you up and running.\n That term still sounds goofy to me, but I suppose I\u0026rsquo;m just showing my age. [return] I ended up solving those issues. And then I had issues uninstalling CUDA 9.2 but there\u0026rsquo;s no need to reopen those wounds. [return] The NVIDIA Cloud PyTorch container image runs CUDA 10 and has a preview of features from PyTorch 1.0. But it\u0026rsquo;s based on Ubuntu 16.04. 🤷‍♂️ [return] Samir Jabari from Friedrich-Alexander Universitat—unfortunately the blog posts associated with this repo are now returning 404. [return]   ",
                "date_published": "2018-11-11T12:38:01-07:00"
            }
            , {
                "title": "It's Been Real, Octopress",
                "id": "https://negativesign.com/blog/2018/07/09/its-been-real-octopress/",
                "url": "https://negativesign.com/blog/2018/07/09/its-been-real-octopress/",
                "summary": "Just finished moving ye old blog from Octopress to Hugo under the premise that I\u0026rsquo;d write and publish a little more if I could use a tool that is is a little more modern.1 You know, more modern than a vintage 2012 Ruby.\nI took a look at other options before I took the leap—Nikola and a couple other Python-based systems looked promising. I started hacking around with Nikola before deciding it didn\u0026rsquo;t feel quite right.",
                
                "content_html": "\u003cp\u003eJust finished moving \u003cem\u003eye old blog\u003c/em\u003e from \u003ca href=\"http://octopress.org\"\u003eOctopress\u003c/a\u003e to \u003ca href=\"https://gohugo.io\"\u003eHugo\u003c/a\u003e under the premise that I\u0026rsquo;d write and publish a little more if I could use a tool that is is a little more modern.\u003csup class=\"footnote-ref\" id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\"\u003e1\u003c/a\u003e\u003c/sup\u003e You know, more modern than a vintage 2012 Ruby.\u003c/p\u003e\n\n\u003cp\u003eI took a look at other options before I took the leap—\u003ca href=\"https://getnikola.com\"\u003eNikola\u003c/a\u003e and a couple other Python-based systems looked promising. I started hacking around with Nikola before deciding it didn\u0026rsquo;t feel quite right.\u003c/p\u003e\n\n\u003cp\u003eHugo has been a joy to use so far. I don\u0026rsquo;t know if it\u0026rsquo;s just that I\u0026rsquo;ve got an extra six years of programming under my belt, but the system seems to be more intuitive than I remember Octopress/Jekyll being. It\u0026rsquo;s got great documentation and forums to boot. I was able to convert my entire blog over, including manually editing some blog posts and hacking away at a new design/layout over the course of a weekend. I even managed to make it segfault!\u003c/p\u003e\n\n\u003cp\u003eI\u0026rsquo;m pretty jazzed that Hugo can \u003ca href=\"https://github.com/knowsuchagency/hugo_jupyter\"\u003epublish Jupyter Notebooks\u003c/a\u003e. It also seems like a good way forward for \u003ca href=\"https://micro.blog\"\u003ehosting a microblog\u003c/a\u003e and moving away from Twitter a little.\u003c/p\u003e\n\n\u003cp\u003eThanks to \u003ca href=\"https://theconfused.me/\"\u003eLingyi Hu\u003c/a\u003e for developing the \u003ca href=\"https://themes.gohugo.io/er/\"\u003eEr theme\u003c/a\u003e that I hacked at to make this update. There are still a few things to clean up, but overall I\u0026rsquo;m happy with the fresh look.\u003c/p\u003e\n\u003cdiv class=\"footnotes\"\u003e\n\n\u003chr /\u003e\n\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003eAt time of writing, the first item on the Octopress website is an article titled \u003ca href=\"http://octopress.org/2015/01/15/octopress-3.0-is-coming/\"\u003eOctopress 3.0 Is Coming\u003c/a\u003e that\u0026rsquo;s dated in January of 2015.\n \u003ca class=\"footnote-return\" href=\"#fnref:1\"\u003e\u003csup\u003e[return]\u003c/sup\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
                "content_text": "Just finished moving ye old blog from Octopress to Hugo under the premise that I\u0026rsquo;d write and publish a little more if I could use a tool that is is a little more modern.1 You know, more modern than a vintage 2012 Ruby.\nI took a look at other options before I took the leap—Nikola and a couple other Python-based systems looked promising. I started hacking around with Nikola before deciding it didn\u0026rsquo;t feel quite right.\nHugo has been a joy to use so far. I don\u0026rsquo;t know if it\u0026rsquo;s just that I\u0026rsquo;ve got an extra six years of programming under my belt, but the system seems to be more intuitive than I remember Octopress/Jekyll being. It\u0026rsquo;s got great documentation and forums to boot. I was able to convert my entire blog over, including manually editing some blog posts and hacking away at a new design/layout over the course of a weekend. I even managed to make it segfault!\nI\u0026rsquo;m pretty jazzed that Hugo can publish Jupyter Notebooks. It also seems like a good way forward for hosting a microblog and moving away from Twitter a little.\nThanks to Lingyi Hu for developing the Er theme that I hacked at to make this update. There are still a few things to clean up, but overall I\u0026rsquo;m happy with the fresh look.\n At time of writing, the first item on the Octopress website is an article titled Octopress 3.0 Is Coming that\u0026rsquo;s dated in January of 2015. [return]   ",
                "date_published": "2018-07-09T01:31:40-06:00"
            }
            , {
                "title": "Building AVG DAY Again",
                "id": "https://negativesign.com/blog/2018/01/03/building-avg-day-again/",
                "url": "https://negativesign.com/blog/2018/01/03/building-avg-day-again/",
                "summary": "A few weeks back I went to a meetup where people, uh, meet, to talk about artistic projects they\u0026rsquo;re working on and critique each other\u0026rsquo;s work. I took some prints of my AVG DAY project from last year and got some really good feedback.\nHere is the question that stood out most to me: what do multiple exposures look like as images are added to the exposure? I heard that same question in some form throughout the year as I showed people the project and I this as well: how are the puzzling elements of these images formed?",
                
                "content_html": "\n\n\u003cp\u003eA few weeks back I went to a \u003ca href=\"https://www.meetup.com/workinprogress/\"\u003emeetup\u003c/a\u003e where people, uh, meet, to talk about artistic projects they\u0026rsquo;re working on and critique each other\u0026rsquo;s work. I took some \u003ca href=\"https://thisisreal.net/2017/02/25/\"\u003eprints\u003c/a\u003e of my \u003ca href=\"https://thisisreal.net/avgday\"\u003eAVG DAY\u003c/a\u003e \u003ca href=\"https://negativesign.com/blog/2017/01/15/avg-day/\"\u003eproject\u003c/a\u003e from last year and got some really good feedback.\u003c/p\u003e\n\n\u003cp\u003eHere is the question that stood out most to me: what do multiple exposures look like as images are added to the exposure? I heard that same question in some form throughout the year as I showed people the project and I this as well: how are the puzzling elements of these images formed?\u003c/p\u003e\n\n\u003cp\u003eOne easy way to answer this question would be to build a multiple exposure for each day that had multiple photos associated with it.\u003c/p\u003e\n\n\u003ch2 id=\"script-mechanics\"\u003eScript Mechanics\u003c/h2\u003e\n\n\u003cp\u003eThe code \u003ca href=\"https://negativesign.com/blog/2017/02/13/building-avg-day/\"\u003eI described last year\u003c/a\u003e served as a foundation for this new goal. I just needed to do a little metadata reading and book keeping to organize the photos from an entire month into groups of photos for each day. Once that was done it was trivial to call the averaging function on each group of images individually. Cool.\u003c/p\u003e\n\n\u003cp\u003eAnother bit of feedback I received concerned whether the color of the multiple exposure images changed as the year went on. The way I processed the images last year made it impossible to answer that question. By performing averaging/histogram equalization on each color channel individually I completely destroyed the color balance present in each individual image. Rookie mistake!\u003c/p\u003e\n\n\u003cp\u003eI tried several different ways of doing the histogram equalization (including converting to a different colorspace and only performing equalization on the luminance or value channel, using a contrast-limited adaptive histogram equalization function) but in general those methods created images with too much contrast and displeasing color.\u003c/p\u003e\n\n\u003cp\u003eI settled on a much simpler technique: what \u003ccode\u003escikit-image\u003c/code\u003e calls \u0026ldquo;contrast stretching.\u0026rdquo; Essentially, calculate where the vast majority of the dynamic range in the multiple exposure lies and then force it to span the dynamic range of its storage data type. I know I\u0026rsquo;ll anger some pedants by making the following analogy, but it\u0026rsquo;s kind of like applying a compressor to a vocal track.\u003c/p\u003e\n\n\u003cp\u003eThis seemed to make the multiple exposures with fewer than eight component images look like I expected, some with \u003ca href=\"https://thisisreal.net/avgday2017/11/29/\"\u003estunning results\u003c/a\u003e. Using this technique to generate a multiple exposure for an entire month resulted in browns and other muted tones that might be expected if you mix a bunch of colors together. While this result is arguably \u0026ldquo;more correct\u0026rdquo;, I am undecided if it is an improvement over the method employed last year.\u003c/p\u003e\n\n\u003cp\u003eOne thing I didn\u0026rsquo;t do (but really should) is convert from sRGB or AdobeRGB to linear RGB before performing any image altering calculations and then converting it back.\u003c/p\u003e\n\n\u003ch2 id=\"finishing-touches\"\u003eFinishing Touches\u003c/h2\u003e\n\n\u003cp\u003eAfter I settled on the image processing approach I took a beat and thought about what I should do with all the images that would be generated. The natural place for them is my \u003ca href=\"https://thisisreal.net/imglib\"\u003eimage portfolio\u003c/a\u003e and the way to get them there is to upload them to flickr with carefully crafted metadata.\u003c/p\u003e\n\n\u003cp\u003eI have a few cusswords about dealing with image metadata in Python. In order to group the images by day I needed to get at the machine tags I added to the source images, and those tags are stored in IPTC metadata. It seems there are no Python3-ready libraries that will compile on a Mac and reliably read IPTC data. The approach I ended up taking was to install \u003ca href=\"http://www.exiv2.org\"\u003e\u003ccode\u003eexiv2\u003c/code\u003e\u003c/a\u003e (using \u003ca href=\"https://brew.sh/\"\u003eHomebrew\u003c/a\u003e), make calls to \u003ccode\u003eexiv2\u003c/code\u003e from the shell and parse standard out. To write metadata I generated a text file that contained \u003ccode\u003eexiv2\u003c/code\u003e commands and then called \u003ccode\u003eexiv2\u003c/code\u003e from the shell. Painful, but reliable for my use case.\u003c/p\u003e\n\n\u003cp\u003ePutting this project together was fun and the results are gratifying. A survey of the output goes a long way towards answering the general question posed above. It\u0026rsquo;s also instructive about what photographic elements combine to make compelling multiple exposures. This has already influenced the daily photos I\u0026rsquo;ve taken since.\u003c/p\u003e\n",
                "content_text": " A few weeks back I went to a meetup where people, uh, meet, to talk about artistic projects they\u0026rsquo;re working on and critique each other\u0026rsquo;s work. I took some prints of my AVG DAY project from last year and got some really good feedback.\nHere is the question that stood out most to me: what do multiple exposures look like as images are added to the exposure? I heard that same question in some form throughout the year as I showed people the project and I this as well: how are the puzzling elements of these images formed?\nOne easy way to answer this question would be to build a multiple exposure for each day that had multiple photos associated with it.\nScript Mechanics The code I described last year served as a foundation for this new goal. I just needed to do a little metadata reading and book keeping to organize the photos from an entire month into groups of photos for each day. Once that was done it was trivial to call the averaging function on each group of images individually. Cool.\nAnother bit of feedback I received concerned whether the color of the multiple exposure images changed as the year went on. The way I processed the images last year made it impossible to answer that question. By performing averaging/histogram equalization on each color channel individually I completely destroyed the color balance present in each individual image. Rookie mistake!\nI tried several different ways of doing the histogram equalization (including converting to a different colorspace and only performing equalization on the luminance or value channel, using a contrast-limited adaptive histogram equalization function) but in general those methods created images with too much contrast and displeasing color.\nI settled on a much simpler technique: what scikit-image calls \u0026ldquo;contrast stretching.\u0026rdquo; Essentially, calculate where the vast majority of the dynamic range in the multiple exposure lies and then force it to span the dynamic range of its storage data type. I know I\u0026rsquo;ll anger some pedants by making the following analogy, but it\u0026rsquo;s kind of like applying a compressor to a vocal track.\nThis seemed to make the multiple exposures with fewer than eight component images look like I expected, some with stunning results. Using this technique to generate a multiple exposure for an entire month resulted in browns and other muted tones that might be expected if you mix a bunch of colors together. While this result is arguably \u0026ldquo;more correct\u0026rdquo;, I am undecided if it is an improvement over the method employed last year.\nOne thing I didn\u0026rsquo;t do (but really should) is convert from sRGB or AdobeRGB to linear RGB before performing any image altering calculations and then converting it back.\nFinishing Touches After I settled on the image processing approach I took a beat and thought about what I should do with all the images that would be generated. The natural place for them is my image portfolio and the way to get them there is to upload them to flickr with carefully crafted metadata.\nI have a few cusswords about dealing with image metadata in Python. In order to group the images by day I needed to get at the machine tags I added to the source images, and those tags are stored in IPTC metadata. It seems there are no Python3-ready libraries that will compile on a Mac and reliably read IPTC data. The approach I ended up taking was to install exiv2 (using Homebrew), make calls to exiv2 from the shell and parse standard out. To write metadata I generated a text file that contained exiv2 commands and then called exiv2 from the shell. Painful, but reliable for my use case.\nPutting this project together was fun and the results are gratifying. A survey of the output goes a long way towards answering the general question posed above. It\u0026rsquo;s also instructive about what photographic elements combine to make compelling multiple exposures. This has already influenced the daily photos I\u0026rsquo;ve taken since.\n",
                "date_published": "2018-01-03T23:58:00-06:00"
            }
            , {
                "title": "2017 in Review",
                "id": "https://negativesign.com/blog/2017/12/31/2017-in-review/",
                "url": "https://negativesign.com/blog/2017/12/31/2017-in-review/",
                "summary": "Nothing like a bulleted list to make you feel good about your year. But seriously—I wanted to get one more item on the blog before the calendar turns and reviewing my year seems like a good way to close out 2017.\nIn the past I was required to write out a list of accomplishments twice a year for performance evaluations. Every time I did that I ended up writing thousands of words and I was surprised by the number of large accomplishments that I somehow completely forgot about.",
                
                "content_html": "\u003cp\u003eNothing like a bulleted list to make you feel good about your year. But seriously—I wanted to get one more item on the blog before the calendar turns and reviewing my year seems like a good way to close out 2017.\u003c/p\u003e\n\n\u003cp\u003eIn the past I was required to write out a list of accomplishments twice a year for performance evaluations. Every time I did that I ended up writing thousands of words and I was surprised by the number of large accomplishments that I somehow completely forgot about.\u003c/p\u003e\n\n\u003cp\u003eThis was a big year; lots of important events I don\u0026rsquo;t want to forget. I accomplished a ton, I had a huge life change in the form of a new job, and my best friends got married. Some specifics:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eTook a class on \u003ca href=\"https://thisisreal.net/2017/01/20/\"\u003ealgorithms and data structures\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eTook a class on \u003ca href=\"https://thisisreal.net/2017/02/04/\"\u003estatistical learning techniques\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2017/06/19/\"\u003eTook a class\u003c/a\u003e on modern machine learning tools\u003c/li\u003e\n\u003cli\u003eOpen-sourced some \u003ca href=\"https://github.com/whlteXbread/photoManip\"\u003eimage processing code\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eCelebrated my dad\u0026rsquo;s \u003ca href=\"https://thisisreal.net/2017/04/08/\"\u003e60th birthday\u003c/a\u003e in Snowbird\u003c/li\u003e\n\u003cli\u003eServed as best man for \u003ca href=\"https://thisisreal.net/2017/04/28/\"\u003eSteven\u0026rsquo;s\u003c/a\u003e and  \u003ca href=\"https://thisisreal.net/2017/07/01/\"\u003eDustin\u0026rsquo;s wedding\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eMet Christina\u0026rsquo;s \u003ca href=\"https://thisisreal.net/2017/05/03/\"\u003efriends and family in Ohio\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eWatched my good friend \u003ca href=\"https://thisisreal.net/2017/05/28/\"\u003eBri get married\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2017/05/31/\"\u003eBought a new car\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2017/06/25/\"\u003eSold the car\u003c/a\u003e I\u0026rsquo;ve had for 15 years\u003c/li\u003e\n\u003cli\u003eBefore I moved on from my job at NTIA, I:\n\n\u003cul\u003e\n\u003cli\u003eLed a project to develop a signal processing engine\u003c/li\u003e\n\u003cli\u003eFacilitated a \u003ca href=\"https://www.its.bldrdoc.gov/publications/3190.aspx\"\u003emassive crowdsourcing test\u003c/a\u003e, possibly the largest MRT to date (150,000 trials!)\u003c/li\u003e\n\u003cli\u003ePlanned a long-term research project on IoT radio-frequency interference issues\u003c/li\u003e\n\u003cli\u003eContributed to a five year research plan in the areas of audio and video quality\u003c/li\u003e\n\u003cli\u003eSysadmin on like, so many machines\u003c/li\u003e\n\u003cli\u003eServed as the main point of contact for a Colorado School of Mines capstone project\u003c/li\u003e\n\u003cli\u003eContributed to a survey document on the state of encryption technologies (!)\u003c/li\u003e\n\u003cli\u003eContributed to two NTIA \u003ca href=\"https://www.its.bldrdoc.gov/publications/3168.aspx\"\u003etechnical\u003c/a\u003e \u003ca href=\"https://www.its.bldrdoc.gov/publications/3190.aspx\"\u003edocuments\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eAttended delicious \u003ca href=\"https://thisisreal.net/2017/06/17/\"\u003epopup\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2017/08/12/\"\u003edinners\u003c/a\u003e at MCA Denver\u003c/li\u003e\n\u003cli\u003eSaw the \u003ca href=\"https://thisisreal.net/2017/08/21/\"\u003emoon darken the sun\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eCelebrated my \u003ca href=\"https://thisisreal.net/2017/08/26/\"\u003e34th birthday\u003c/a\u003e a \u003ca href=\"https://thisisreal.net/2017/09/01/\"\u003ecouple times\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://thisisreal.net/2017/09/05/\"\u003eSettled into a new job\u003c/a\u003e with the title \u0026ldquo;Computer Vision and Machine Learning Scientist\u0026rdquo;\n\n\u003cul\u003e\n\u003cli\u003eWrote code to analyze fields of crops and extract useful information\u003c/li\u003e\n\u003cli\u003eDesigned and built a \u003ca href=\"https://thisisreal.net/2017/12/08/\"\u003eGIS and image processing pipeline\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eSysadmin on like, one machine\u003c/li\u003e\n\u003cli\u003eOther stuff too\u003c/li\u003e\n\u003c/ul\u003e\u003c/li\u003e\n\u003cli\u003eSaw some \u003ca href=\"https://thisisreal.net/2017/10/10/\"\u003eepic\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2017/10/22/\"\u003econcerts\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eHiked a \u003ca href=\"https://thisisreal.net/2017/10/28/\"\u003efair\u003c/a\u003e \u003ca href=\"https://thisisreal.net/2017/12/10/\"\u003eamount\u003c/a\u003e (and apparently grew my hair really long)\u003c/li\u003e\n\u003cli\u003ePosted more than \u003ca href=\"https://thisisreal.net/2017/\"\u003e320 dailies\u003c/a\u003e (a new record!)\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eI know there are things that I left out—and maybe I\u0026rsquo;ll update this later—but it was nice to spend some time reflecting on the year and reaping some returns on the investment I\u0026rsquo;ve made in \u003ca href=\"https://negativesign.com/blog/2015/02/08/thoughts-on-five-years-of-daily-photos/\"\u003erecording what happens most days\u003c/a\u003e for the eighth year running.\u003c/p\u003e\n",
                "content_text": "Nothing like a bulleted list to make you feel good about your year. But seriously—I wanted to get one more item on the blog before the calendar turns and reviewing my year seems like a good way to close out 2017.\nIn the past I was required to write out a list of accomplishments twice a year for performance evaluations. Every time I did that I ended up writing thousands of words and I was surprised by the number of large accomplishments that I somehow completely forgot about.\nThis was a big year; lots of important events I don\u0026rsquo;t want to forget. I accomplished a ton, I had a huge life change in the form of a new job, and my best friends got married. Some specifics:\n Took a class on algorithms and data structures Took a class on statistical learning techniques Took a class on modern machine learning tools Open-sourced some image processing code Celebrated my dad\u0026rsquo;s 60th birthday in Snowbird Served as best man for Steven\u0026rsquo;s and Dustin\u0026rsquo;s wedding Met Christina\u0026rsquo;s friends and family in Ohio Watched my good friend Bri get married Bought a new car Sold the car I\u0026rsquo;ve had for 15 years Before I moved on from my job at NTIA, I:  Led a project to develop a signal processing engine Facilitated a massive crowdsourcing test, possibly the largest MRT to date (150,000 trials!) Planned a long-term research project on IoT radio-frequency interference issues Contributed to a five year research plan in the areas of audio and video quality Sysadmin on like, so many machines Served as the main point of contact for a Colorado School of Mines capstone project Contributed to a survey document on the state of encryption technologies (!) Contributed to two NTIA technical documents  Attended delicious popup dinners at MCA Denver Saw the moon darken the sun Celebrated my 34th birthday a couple times Settled into a new job with the title \u0026ldquo;Computer Vision and Machine Learning Scientist\u0026rdquo;  Wrote code to analyze fields of crops and extract useful information Designed and built a GIS and image processing pipeline Sysadmin on like, one machine Other stuff too  Saw some epic concerts Hiked a fair amount (and apparently grew my hair really long) Posted more than 320 dailies (a new record!)  I know there are things that I left out—and maybe I\u0026rsquo;ll update this later—but it was nice to spend some time reflecting on the year and reaping some returns on the investment I\u0026rsquo;ve made in recording what happens most days for the eighth year running.\n",
                "date_published": "2017-12-31T20:08:00-06:00"
            }
            
    ]
    
}