Chris Kuhl's Blog A mix of technical posts and personal updates python-feedgen en Sat, 18 Aug 2018 23:57:57 +0000 Running python from a database <p>While having my morning coffee, I had a strange idea. Is it possible to run code stored inside a sqlite database? I had no idea if it was possible, but I was curious. So I wrote a little project to find out.</p> <p>First things first, I needed some code to store in the database. To keep things simple, I wrote a basic hello world in <code></code>.</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Hello world!&#39;</span><span class="p">)</span> </pre></div> </td></tr></table> <p>With that out of the way, now we need somewhere to store our code. I use <a href="">Peewee</a> as an ORM out of convenience. So we create a basic table with a module name and code field.</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="kn">import</span> <span class="nn">sqlite3</span> <span class="kn">from</span> <span class="nn">peewee</span> <span class="k">import</span> <span class="n">SqliteDatabase</span><span class="p">,</span> <span class="n">Model</span><span class="p">,</span> <span class="n">TextField</span><span class="p">,</span> <span class="n">CharField</span> <span class="n">db</span> <span class="o">=</span> <span class="n">SqliteDatabase</span><span class="p">(</span><span class="s1">&#39;code.db&#39;</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Module</span><span class="p">(</span><span class="n">Model</span><span class="p">):</span> <span class="n">name</span> <span class="o">=</span> <span class="n">CharField</span><span class="p">()</span> <span class="n">code</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">()</span> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span> <span class="n">database</span> <span class="o">=</span> <span class="n">db</span> <span class="n">db</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> <span class="n">db</span><span class="o">.</span><span class="n">create_tables</span><span class="p">([</span><span class="n">Module</span><span class="p">])</span> </pre></div> </td></tr></table> <p>With the table set up, we can load our code into it.</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1 2 3</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> <span class="n">demo_module</span> <span class="o">=</span> <span class="n">Module</span><span class="p">(</span><span class="n">code</span><span class="o">=</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;demo&#39;</span><span class="p">)</span> <span class="n">demo_module</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> </pre></div> </td></tr></table> <p>Now for the secret sauce: getting the code back out. With Python&rsquo;s built-in <a href="">imp</a> module, you can access the internals for importing code, which is exactly what we need to import our module from the database as though it was from a file. First we create an empty module with our desired name. Then we execute our code, assigning the output into the module. Since Python modules are actually dictionaries, executing the module means running any code that is runnable, and otherwise mapping function names, etc. to their code. This is why a lot of code has the <code>if __name__ == '__main__':</code> guard. Lastly we return the module, allowing it to be bound to a name (equivalent to <code>import x as y</code>).</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1 2 3 4 5 6</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="k">def</span> <span class="nf">import_code</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">code</span><span class="p">):</span> <span class="n">module</span> <span class="o">=</span> <span class="n">imp</span><span class="o">.</span><span class="n">new_module</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="n">exec</span><span class="p">(</span><span class="n">code</span><span class="p">)</span> <span class="ow">in</span> <span class="n">module</span><span class="o">.</span><span class="vm">__dict__</span> <span class="k">return</span> <span class="n">module</span> </pre></div> </td></tr></table> <p>With all that out of the way, we can import our code from the database!</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1 2</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="n">m</span> <span class="o">=</span> <span class="n">Module</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="n">import_code</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">m</span><span class="o">.</span><span class="n">code</span><span class="p">)</span> </pre></div> </td></tr></table> <p>The reveal:</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1 2</pre></div></td><td class="code"><div class="codehilite"><pre><span></span>$ python Hello world! </pre></div> </td></tr></table> <p>Cool!</p> <p>If you want to take a look at the full script yourself, you can find it as a <a href="">gist on GitHub</a>.</p> <h2>Uses</h2> <p>Truth be told, I still cannot think of any solid uses for this. Still, it was fun to find out that it&rsquo;s possible to run code from the database. Who knows, this knowledge might just come in handy in the future!</p> Fri, 15 Jun 2018 09:35:00 -0500 Notes for an out-of-province student <p>Last year at the end of November, I got an offer for a co-op placement with a company in Vancouver. Starting January second. Short notice, but also exciting.</p> <p>I had never lived outside of Ontario before, and didn&rsquo;t know too much about anything. So I started asking everyone I knew for advice. Friends, family, friends-of-friends, everyone had something to say. However not everyone has <em>good</em> advice.</p> <p>Having been there and back now, I have written up some notes on what I found useful. Thanks goes to family, friends, friends-of-friends, and even strangers that shared some of their knowledge.</p> <h2>Before you go</h2> <h3>Gear up</h3> <p>The single best piece of advice I got was to buy a rain jacket. Already have one? Buy a <em>real</em> rain jacket. The insistence at first seemed over the top. I can now say however that they are worth every penny. It is not the intensity of rain but the consistency that will soak through your regular old &ldquo;jacket&rdquo;. Gore-Tex is a beautiful thing. The ideal rain jacket should sound like you are wearing a <a href="">Sun Chips bag</a> at first. Eventually it will break in and stop being so noisy. Eventually.</p> <p>A close second to the rain jacket is a pair of waterproof shoes. Whether boots, hiking shoes, or something else, you will be walking in the rain at some point. There is absolutely nothing worse than wet feet. While I went with boots, I would buy hiking shoes if I had to do it again.</p> <h3>Housing</h3> <p>The market is as bad as it sounds. Especially for co-op students, looking for a four or eight month rental. You really can&rsquo;t be picky. That being said, you can still get an okay place short notice. Thanks to UBC and Simon Fraser University being nearby, there are a good amount of students living nearby, and you can usually find an empty room. Yes, it will be more expensive than housing at school.</p> <p>As important as distance for housing, keep an eye on what main transit lines are nearby. You can be twice as far, but if you are living on an express line you can commute around the city just as quickly. The key streets to look at are Main and Cambie.</p> <h3>Packing</h3> <p>Bring less clothing. Moving out I packed a full 50 pound suitcase of clothing, and in retrospect that was too much. Even only four months is enough time to accumulate new clothes, souvenirs, and all sorts of things. Pack less, and make your way to a thrift store the first day or two after you move out.</p> <h3>Cost</h3> <p>Finally, make peace with the fact that you will spend a fair bit of money. Not just on housing and food, but also on all of the experiences that are so close to you. When you can take public transit to skiing, it is very difficult to <em>not</em> go at least once. In addition, with Seattle so close, and Victoria even closer, you will have many opportunities to travel and spend even more.</p> <h2>Once you get there</h2> <h3>Transit</h3> <p>Buy a bicycle! Even though Vancouver already has world-class public transit, having a bike lets you go much further, on your own terms.</p> <p>Sign up for ZipCar. You rent cars by the minute, with a daily cap. You don&rsquo;t really need them for in Vancouver, but they are critical if you want to do something further away for a day or even a weekend.</p> <h3>Keep in touch</h3> <p>Make an effort to keep in touch with family or friends. While the time zones are only three hours apart, that is enough to make a big difference. When everyone is working before you even wake up, you have few chances to catch up with others naturally. Plan some phone calls, skype chats, gaming sessions, or whatever you need to catch up.</p> <h3>Enjoy it!</h3> <p>Be a tourist. Do it shamelessly. I bought the <a href="">Lonely Planet Pocket Vancouver</a> book, although any guide will work. Having a reference of things to do nearby when you&rsquo;re wandering around the city is fantastic for when you have a lull in your day. You don&rsquo;t have to do everything, or even anything in the guidebook. Often finding a place the next door down from a recommended one is nearly as good, at a fraction of the price.</p> <p>Finally, plan big things in advance. It is easy to do things around the city spontaneously, but larger plans take some time. Visiting Seattle or Victoria is worth the extra effort &ndash; both are beautiful cities and completely different than Vancouver in their own ways.</p> Fri, 04 May 2018 11:06:00 -0500 How does Flask work? <p>When you first start using the <a href="">Flask framework</a> it feels a little magical. You write a function to return some text, add a single line above it, call run, and your text is somehow being sent to your web browser! Most introductions will show you a little sample of code something like this.</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1 2 3 4 5 6 7 8 9 10 11</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="kn">from</span> <span class="nn">flask</span> <span class="k">import</span> <span class="n">Flask</span> <span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>   <span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span> <span class="k">def</span> <span class="nf">hello</span><span class="p">():</span> <span class="k">return</span> <span class="s2">&quot;Hello World!&quot;</span>   <span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span> <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> </pre></div> </td></tr></table> <p>At most you&rsquo;ll get a handwavy explanation that <code>@app.route</code> defines URLs, and usually you are just expected to accept that that is how it works. Now certainly that is enough to start adding more code that usually works. However personally it bugs me. How does Flask know to serve my content at that URL?</p> <p>I find it easiest to start from as high up as possible and work my way down the chain of calls until it all starts making sense. So we start with the last function what is called: <code></code>.</p> <h2>Off and run()-ing</h2> <p><code></code> isn&rsquo;t too exciting itself. It takes a number of optional parameters (for example, whether debug mode is set, or what port to operate on) and then sets them inside the Flask object. Right at the end it imports <a href="">Werkzeug</a>, and then calls <code>run_simple(host, port, self, **options)</code>.</p> <p>Inside of <code>run_simple</code> we see more setting up. This is focused on the server though. In addition, it defines a few internal functions. The key function is <code>inner()</code>, which creates a server. It calls <code>make_server</code>, passes it the Flask application and then runs it in a loop.</p> <p>Depending on what optional parameters are passed into it, <code>make_server</code> creates one of several kinds of servers. ThreadingWSGIServer, ForkingWSGIServer, or in our case, BaseWSGIServer. This is a subclass of Python&rsquo;s builtin HTTPServer object. This server includes the <a href="">Web Server Gateway Interface</a> (WSGI), which is a standardized API for Python frameworks to communicate with webservers.</p> <p>In essence, a server implementing WSGI will call the <code>__call__(environ, start_response)</code> method on the application it has been passed. To dig deeper, <code>environ</code> is a dictionary of CGI variables (CGI itself being a language-agnostic predecessor to WSGI, and an initialism for <a href=""><em>Common Gateway Interface</em></a>). <code>start_response</code> is a function that returns a tuple of an HTTP status code, and the headers to respond with.</p> <h2>How does Flask handle <code>__call__</code>s?</h2> <p><code>Flask.__call__</code> is actually a thin wrapper around another function, <code>Flask.wsgi_app</code>. This is done so that middleware (add-ons that can intercept the messages between the WSGI server and application, and extend them) can be applied. After doing some error handling, this calls the internal function <code>full_dispatch_request</code></p> <p>Here we do some more error handling, before call <code>dispatch_request</code>, which is the real focus. This gets the request and the URL associated with the request. Then it looks up the URL in an internal map for functions that handle requests, and calls the corresponding function for that URL with the view arguments.</p> <h2>What functions?</h2> <p>Now where does the map of URLs come from? <a href="">Decorators!</a></p> <p>Moving upwards from the bottom of our sample, we look into <code>@app.route("/")</code> now. This is a function decorator (that is, a function that takes a function as input and returns a (possibly modified) function).</p> <p>Our <code>route</code> decorator takes a rule (parameterized URL as a string), the view function (hello in our case), and other optional parameters. From there we call the internal function <code>add_url_rule</code>.</p> <p>This creates a Rule object (from Werkzeug). This is a wrapper for the parameterized URL string and the other optional arguments. For example, by creating Rules we can have different views defined for the same URL depending on whether the brower request is <code>GET</code> or <code>POST</code>. These rules are then added to the internal map <code>self.url_map</code>, which is what Flask&rsquo;s <code>__call__</code> method looks up URLs in!</p> <p>The cycle is complete! With this adventure, we&rsquo;ve dug (with excruciating detail) into what Flask <em>does</em> when you run the simple application. While this information may not be useful when writing your own Flask application, it is very good to know. Being able to dig into the guts of your application and know what it is actually doing has been incredibly valuable in efficiently debugging Flask when things stop going according to plan.</p> <p>Did I miss something, or mess up a detail? Appreciate it? I&rsquo;d <a href="">love to hear</a> from you if you have any comments on this article!</p> Wed, 28 Mar 2018 20:41:00 -0800 JSON in PostgreSQL <p>Recently at work, I got into a discussion about whether it makes sense to store JSON objects in a relational database. While I tried to disagree, they presented a some convincing arguments. However now that I have had time to think, I feel as though the arguments also have a few flaws.</p> <p>Their first argument was that JSON objects are easier to change in the future. For example, if we had initially assumed that a User can only have one address, adding a second is as simple as updating the object. No need for database migrations. It makes sense. However a problem still exists: how do you access the address on a User? Instead of being a single value, it&rsquo;s now a list of values. To handle this we need to either modify every existing User, or handle it in the backend. If we modify every object though, we have effectively written a database migration. So this is no easier than simply storing our addresses in a flat table. On the other hand, if we handle this in the backend, there&rsquo;s a real risk of an exponential increase in complexity. Having two address formats means there are two ways through the code. If we do this 5 more times, we have 64 different paths through the code. The overhead and number of errors is even worse than the temporary headache of writing database migrations. By using JSON you effectively move the schema for data from the database to the backend. Where the schema can be enforced automatically with types in the DB, it is moved into the developer&rsquo;s mindspace with JSON, adding one more thing that has to be remembered while dealing with the data.</p> <p>The other argument presented was that by storing JSON objects, we can store many types of the same objects. Instead of having a separate table for British Columbian driver&rsquo;s licences, Ontarian driver&rsquo;s licences, and every other kind, we could simple store them all in a JSON column on our User. However even though many things in life may look similar, they may have completely different properties. If we store all driver&rsquo;s licences as a single JSON object in a column, it is simple to return a driver&rsquo;s licence. However, what if in the future, a province allows people to use their licence as a health card? Looking up a person&rsquo;s health insurance now became much more difficult, as you need to inspect inside each driver&rsquo;s licence object to determine if that person (1) has that province&rsquo;s card and (2) uses it as a health card. While this is a contrived example, I feel the risk cannot be understated. While at the point of development all use cases could be enumerated, as the world changes you are left exposed to changes in the outside world.</p> <p>Despite my complaints, I would agree that JSON (and NoSQL) are hugely valuable for allowing faster iteration when creating a prototype. That same speed of iteration however makes it easier to end up worse off than you could end up with a relational database.</p> Sat, 24 Mar 2018 22:01:00 -0800 Facebook cannot act in your best interest <p>With the recent complaints about Facebook surfacing across the internet, now seems as good of a time as ever to share this. I&rsquo;ve discussed with friends before that Facebook <em>cannot</em> be acting in their best interest.</p> <p>Now everyone agrees that Facebook is in the business of making money. That&rsquo;s the entire purpose of for-profit enterprises. It&rsquo;s also not controversial to say that Facebook makes its money by advertising.</p> <p>Based on these two statements, we can say that to please shareholders Facebook must show advertisements. In particular, they should show as many advertisements as possible, in order to make as much money as possible.</p> <p>In order sell more advertisements, Facebook must do one (or some combination) of two things: acquire more users and show more advertisements to existing users. With Facebook&rsquo;s already having a user base of billions of users, it is less and less likely that Facebook can continue to drive growth by adding more users in the future. So then to make more money, it must show more advertisements to existing users.</p> <p>Now in order to show more advertisements to existing users, you can either increase the concentration of advertisements, or increase the amount of time spent on it. Increasing the concentration of advertisements will drive away some portion of users (as there is always some users at the margins, for whom more ads would be the &ldquo;straw that breaks the camels back&rdquo;). So it is in Facebook&rsquo;s interest to maintain their existing density of advertisements, and instead have users spend more time on it.</p> <p>We&rsquo;ve established that Facebook wants people to spend as much time as possible on it. At this point, I usually ask my friends about examples of where they have spent more time than usual on Facebook. Often it comes back to some impossible political argument, or family blow-up, or some other unpleasant thing. These are the things that we ask Facebook to show us more of, by spending more time looking at. The problem is that the things that draw our attention &mdash; anger, violence, fear &mdash; are not the things that are good for us to be immersed in.</p> Tue, 20 Mar 2018 21:15:00 -0800 Respectful Tracking <p>As a university student in a co-op program, I am either working a co-op job, or preparing to start applying to the next one. Sometimes both at the same time. I have been working on this site to provide a portfolio of some of my past projects, and of my writing. However I faced a problem. How would I know if my site was actually capturing users or not? Of course I could use Google Analytics, however I didn&rsquo;t like the idea of trusting any third party to do something against their own interest. In this case, an advertising company promising not to track third parties.</p> <p>Goal: Implement server-side responses to <a href="">Do Not Track</a> headers, so that if users do not want to be tracked, they will not even see Google Analytics code.</p> <p>Now to do this, I first need to get whether the user has Do Not Track enabled or not, and use that to conditionally render any templates. Thankfully the Flask API makes this dead-simple to do. With the handler <code>@app.context_processor</code> you can define a function to insert variables into the context for ever render request.</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1 2 3 4 5 6 7 8 9</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="c1"># inject Do Not Track header variable for all contexts</span> <span class="nd">@app</span><span class="o">.</span><span class="n">context_processor</span> <span class="k">def</span> <span class="nf">inject_dnt</span><span class="p">():</span> <span class="n">dnt</span> <span class="o">=</span> <span class="kc">False</span> <span class="k">try</span><span class="p">:</span> <span class="n">dnt</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">&#39;DNT&#39;</span><span class="p">]</span> <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span> <span class="k">pass</span> <span class="k">return</span> <span class="p">{</span><span class="s1">&#39;do_not_track&#39;</span><span class="p">:</span> <span class="n">dnt</span><span class="p">}</span> </pre></div> </td></tr></table> <p>With that in place, it&rsquo;s as easy as inserting an if statement into your base template:</p> <table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1 2 3 4 5 6 7 8 9 10</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="cp">{%</span> <span class="k">if</span> <span class="k">not</span> <span class="nv">do_not_track</span> <span class="cp">%}</span> <span class="c">&lt;!-- Global site tag (gtag.js) - Google Analytics --&gt;</span> <span class="nt">&lt;script</span> <span class="err">async</span> <span class="na">src=</span><span class="s">&quot;;</span><span class="nt">&gt;&lt;/script&gt;</span> <span class="nt">&lt;script&gt;</span> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag(&#39;js&#39;, new Date()); gtag(&#39;config&#39;, &#39;UA-XXXXXXXXX-X&#39;); <span class="nt">&lt;/script&gt;</span> <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> </pre></div> </td></tr></table> <p>That&rsquo;s it! If you want to test this out, try enabling / disabling Do Not Track in your web browser, and observing a change in the number of network requests (or just the number on your adblocker) when you reload the page.</p> Fri, 09 Mar 2018 18:53:00 -0800 Thought Experiment: The TextNet <p>On the forums I follow, there has been a growth in people begrudging the &ldquo;JavaScript-ization&rdquo; of modern web content. On one hand I can absolutely agree &ndash; why should loading a text-only recipe take dozens of megabytes? At the same time I feel it is a boon to allow for more efficient development (i.e. allowing developers to focus on development instead of design). But I think that those naysayers are onto something. So what would it look like if we banished all JavaScript from (a segment of) the internet?</p> <h2>The proposal</h2> <p>The TextNet, a text-only portion of the internet. A new <code>.text</code> TLD is introduced. With a covenant that only plain text and HTML can be served from such domains.</p> <h2>What does that mean?</h2> <p>JavaScript doesn&rsquo;t run. It can still be loaded, but it&rsquo;s just a static text file, like everything else. Same for images or files: You can <a href="">Base64</a> encode them, but they will not display. CSS would either be forbidden or restricted to a simple subset.</p> <h2>What effects would this have?</h2> <h3>Fewer advertisements</h3> <p>First and foremost, conventional advertisers would not be attracted to it. Without images for ads, or JavaScript to track users, there is no way to run advertisements. This would prevent the advertising-driven formatting of content. Slideshows of content, &ldquo;Click to read full article&rdquo;, and clickbait would disappear, as there would be no financial incentive to format articles in that way. Who instead would create content? I expect you would see two groups creating content:</p> <h4>Indirect Beneficiaries</h4> <p>Businesses or professionals, creating content for indirect benefits. This could include providing access to news in emergencies (for example when cell towers are overloaded, as text uses little bandwidth, and could still be loaded). For example, <a href="">NPR</a> and <a href="">CNN</a> take this approach. Here they do not benefit directly by providing ad-free articles. Rather they gain a reputation for being available even when a user can not load competitors&rsquo; sites. Professionals self-promoting also fall in this group. Such technical blogs are intended to develop a brand, and signal to employers that the professional is competent.</p> <h4>The Hobbyists and Artists</h4> <p>The other group would be those creating content for the joy of it. The medium of plaintext imposes a set of constraints that allows people to focus their creativity. Similar to using a reduced palette and canvas in <a href="">pixel art</a>, text forces one to focus on the content they produce, instead of the decoration that surrounds it. This category includes both art and technical writing on niche topics, such as <a href="">programming for a Game Boy</a>.</p> <p>In effect, removing advertising as a form of funding content creation would disincentive the creation of low-quality content. In turn this increases the signal-to-noise ratio of the content.</p> <h3>Unconventional consumption</h3> <h4>Sneakernet</h4> <p>Since plaintext is lightweight, the entirety of the TextNet could be save to a single thumb drive. While the <a href="">sneakernet</a> currently exists, being able to save a copy of everything would mean that any and all links within the content would work. This would allow for a more natural &ldquo;exploration&rdquo; of the internet by those without conventional access.</p> <h4>New Ways of Interacting</h4> <p>The magnitude of JavaScript and CSS in modern webpages means that today&rsquo;s web browsers can be used to run entire operating systems in them. The trade-off to this is that you require the resources to run an entire operating system within a browser. By reducing the required overhead from arbitrary scripts and styles to text, new classes of devices could be used to interface with the internet. eReaders would become first-class citizens, allowing months of internet browsing on a single charge. More whimsically, teletypewriters could make a comeback. Print off the web pages you want to read, and when you are done you clear the browser history with a paper shredder.</p> <h2>Conclusion</h2> <p>It is hard to know how a new, restricted medium would be treated. Especially when the goal of such a medium is to encourage the creativity that emerges from restriction. However I feel that such a medium would be a net positive to the world, allowing broader access to the internet, and renewed interest for those burnt out by the current madness.</p> Tue, 19 Dec 2017 19:45:00 -0500 Feed-ing the Readers <p>Initially an <abbr title="Minimum Viable Product">MVP</abbr>, I have been progressively fleshing out my blog as I have time, usually with whatever catches my fancy. My latest (re)discovery on this front has been <abbr title="Rich Site Summary, a way to publish updates to sites in a computer-readable format">RSS</abbr> feeds. Being able to keep up-to-date on blogs that post infrequently is beneficial to me. Not only because I can keep up on content I care about, but also because this form of passive following allows me to use the internet less.</p> <p>With that in mind, my latest update to the site has been to add an <abbr title="Rich Site Summary, a way to publish updates to sites in a computer-readable format">RSS</abbr> feed. Again trying to follow my focus on <a href="/blog/the-easiest-route/">taking the easy way</a>, I used the python library <a href="">feedgen</a> to do all the heavy lifting for me. Combined with FlatPages for flask, and I have another handy feature added to my blog in just under an hour.</p> Thu, 07 Dec 2017 18:12:00 -0500 The Easiest Route <p>My most limited resource when it comes to side projects is not my computing resources or my ideas, but my time. With school obligations it is difficult to find the time to complete my projects. The solution I have found, while often unsatisfactory, is to do things the easy way.</p> <p>To explain, while I am trying to accomplish my goal, anything that isn&rsquo;t directly related to success is a roadblock. For example when I wanted to create my own website with a blog, style wasn&rsquo;t a priority to me. So even though I would love to be able to design it from scratch, I didn&rsquo;t. Designing my website wasn&rsquo;t my goal, writing a blog was (and is).</p> Fri, 24 Nov 2017 18:51:00 -0500 Off and Running! <p>With the recent addition of a working portfolio display, my website is finally at the level of a minimum viable product! While it&rsquo;s not much to look at right now, it at least has some decent copy, and decent code behind the scenes.</p> <p>My goal is to to work on it piecemeal, updating the code at the same time I write more posts for it as well.</p> Tue, 19 Sep 2017 14:49:00 -0500