<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>dencold</title>
    <link>https://www.dencold.com/</link>
    <description>Recent content on dencold</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>This work is licensed under a Creative Commons License</copyright>
    <lastBuildDate>Sat, 04 May 2019 13:16:08 -0700</lastBuildDate>
    <atom:link href="https://www.dencold.com/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Understanding npm package upgrades</title>
      <link>https://www.dencold.com/post/2019/npm-package-upgrades/</link>
      <pubDate>Sat, 04 May 2019 13:16:08 -0700</pubDate>
      
      <guid>https://www.dencold.com/post/2019/npm-package-upgrades/</guid>
      <description>

&lt;p&gt;I maintain a small task management app called &lt;a href=&#34;https://github.com/dencold/attainment-web&#34;&gt;Attainment&lt;/a&gt; that I used to teach myself more about front-end javascript development. It uses the &lt;a href=&#34;https://vuejs.org/&#34;&gt;Vue.js&lt;/a&gt; framework and I use npm to manage my upstream dependencies.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t get much consistent time to hack on it, so it&amp;rsquo;s usually several months in between development cycles. When I come back to the project, I&amp;rsquo;ve invariably found myself asking &amp;ldquo;what&amp;rsquo;s changed and what should I update?&amp;rdquo; when it comes to my dependencies. I&amp;rsquo;ve frequently found myself wondering what the difference is between &lt;code&gt;npm upgrade&lt;/code&gt; and &lt;code&gt;npm update&lt;/code&gt; and how do I figure out &lt;em&gt;what&lt;/em&gt; dependencies are out of date in my web projects. This post is my attempt to learn the best ways to manage this and hopefully it will help others as well.&lt;/p&gt;

&lt;h2 id=&#34;what-s-the-status&#34;&gt;What&amp;rsquo;s the status?&lt;/h2&gt;

&lt;p&gt;My first question is &amp;ldquo;how do I know where I stand&amp;rdquo;. I&amp;rsquo;d like to get a listing of things that are currently out of date. The command to do that is &lt;code&gt;npm outdated&lt;/code&gt;. Here&amp;rsquo;s what it looks like against Attainment after a long period of neglect:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm outdated
Package                 Current  Wanted         Latest  Location
@vue/cli-plugin-babel     3.0.4   3.7.0          3.7.0  attainment-vue
@vue/cli-plugin-eslint    3.0.4   3.7.0          3.7.0  attainment-vue
@vue/cli-service          3.0.4   3.7.0          3.7.0  attainment-vue
bootstrap                 3.3.7   3.4.1          4.3.1  attainment-vue
chartist                 0.10.1  0.10.1         0.11.0  attainment-vue
firebase                  5.5.2  5.11.1         5.11.1  attainment-vue
fuse.js                   3.2.1   3.4.4          3.4.4  attainment-vue
moment                   2.22.2  2.24.0         2.24.0  attainment-vue
node-sass                 4.9.3  4.12.0         4.12.0  attainment-vue
vue                      2.5.17  2.6.10         2.6.10  attainment-vue
vue-datetime              0.7.1   0.7.1  1.0.0-beta.10  attainment-vue
vue-fuse                  1.5.2   1.5.2          2.0.2  attainment-vue
vue-js-modal             1.3.26  1.3.31         1.3.31  attainment-vue
vue-moment                3.2.0   3.2.0          4.0.0  attainment-vue
vue-router                3.0.1   3.0.6          3.0.6  attainment-vue
vue-template-compiler    2.5.17  2.6.10         2.6.10  attainment-vue
vuex                      3.0.1   3.1.0          3.1.0  attainment-vue
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us the dependency in the left most column, followed by the version currently installed, the one we &lt;em&gt;want&lt;/em&gt;, and the latest available version upstream. Why is it that sometimes what we want is not the latest version listed? For example look at the details for &lt;code&gt;bootstrap&lt;/code&gt; from that output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;Package                 Current  Wanted         Latest  Location
bootstrap                 3.3.7   3.4.1          4.3.1  attainment-vue
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The latest version is &lt;code&gt;4.3.1&lt;/code&gt;, but we want &lt;code&gt;3.4.1&lt;/code&gt;. What&amp;rsquo;s up with that? Well, npm understands &lt;a href=&#34;https://semver.org/&#34;&gt;semver&lt;/a&gt; and we have the &amp;ldquo;dependencies&amp;rdquo; section of our &lt;code&gt;package.json&lt;/code&gt; file defined as:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;bootstrap&amp;quot;: &amp;quot;^3.4.1&amp;quot;,
    &amp;quot;chartist&amp;quot;: &amp;quot;^0.10.1&amp;quot;,
    &amp;quot;firebase&amp;quot;: &amp;quot;^5.11.1&amp;quot;,
    &amp;quot;fuse.js&amp;quot;: &amp;quot;^3.4.4&amp;quot;,
    &amp;quot;moment&amp;quot;: &amp;quot;^2.24.0&amp;quot;,
    &amp;quot;vue&amp;quot;: &amp;quot;^2.6.10&amp;quot;,
    &amp;quot;vue-clickaway&amp;quot;: &amp;quot;^2.2.2&amp;quot;,
    &amp;quot;vue-datetime&amp;quot;: &amp;quot;^0.7.1&amp;quot;,
    &amp;quot;vue-fuse&amp;quot;: &amp;quot;^1.5.2&amp;quot;,
    &amp;quot;vue-js-modal&amp;quot;: &amp;quot;^1.3.31&amp;quot;,
    &amp;quot;vue-moment&amp;quot;: &amp;quot;^3.2.0&amp;quot;,
    &amp;quot;vue-router&amp;quot;: &amp;quot;^3.0.6&amp;quot;,
    &amp;quot;vuex&amp;quot;: &amp;quot;^3.1.0&amp;quot;
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that bootstrap is configured with version &lt;code&gt;^3.4.1&lt;/code&gt; this tells npm that we can accept any &lt;strong&gt;patch&lt;/strong&gt; or &lt;strong&gt;minor&lt;/strong&gt; version updates (e.g. anything within the 3.0.0 release) safely. So in the output of &lt;code&gt;npm outated&lt;/code&gt;, above, bootstrap&amp;rsquo;s latest version is &lt;code&gt;4.3.1&lt;/code&gt;, but we&amp;rsquo;ll only accept the latest in the &lt;code&gt;3.0.0&lt;/code&gt; line, which is &lt;code&gt;3.4.1&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;let-s-update&#34;&gt;Let&amp;rsquo;s update!&lt;/h2&gt;

&lt;p&gt;Now that we know &lt;em&gt;what&lt;/em&gt; is out of date, and we know that npm is (hopefully) protecting us from any breaking changes in a major version change, let&amp;rsquo;s update our dependencies. We do this using &lt;code&gt;npm update&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm update
npm WARN deprecated joi@14.3.1: This module has moved and is now available at @hapi/joi. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm WARN deprecated topo@3.0.3: This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm WARN deprecated hoek@6.1.3: This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.

&amp;gt; grpc@1.20.0 install /home/coldwd/src/github.com/dencold/attainment-web/node_modules/grpc
&amp;gt; node-pre-gyp install --fallback-to-build --library=static_library

node-pre-gyp WARN Using request for node-pre-gyp https download 
[grpc] Success: &amp;quot;/home/coldwd/src/github.com/dencold/attainment-web/node_modules/grpc/src/node/extension_binary/node-v67-linux-x64-glibc/grpc_node.node&amp;quot; is installed via remote

&amp;gt; node-sass@4.12.0 install /home/coldwd/src/github.com/dencold/attainment-web/node_modules/node-sass
&amp;gt; node scripts/install.js

Downloading binary from https://github.com/sass/node-sass/releases/download/v4.12.0/linux-x64-67_binding.node
Download complete..] - :
Binary saved to /home/coldwd/src/github.com/dencold/attainment-web/node_modules/node-sass/vendor/linux-x64-67/binding.node
Caching binary to /home/coldwd/.npm/node-sass/4.12.0/linux-x64-67_binding.node

&amp;gt; node-sass@4.12.0 postinstall /home/coldwd/src/github.com/dencold/attainment-web/node_modules/node-sass
&amp;gt; node scripts/build.js

Binary found at /home/coldwd/src/github.com/dencold/attainment-web/node_modules/node-sass/vendor/linux-x64-67/binding.node
Testing binary
Binary is fine
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {&amp;quot;os&amp;quot;:&amp;quot;darwin&amp;quot;,&amp;quot;arch&amp;quot;:&amp;quot;any&amp;quot;} (current: {&amp;quot;os&amp;quot;:&amp;quot;linux&amp;quot;,&amp;quot;arch&amp;quot;:&amp;quot;x64&amp;quot;})

+ fuse.js@3.4.4
+ bootstrap@3.4.1
+ moment@2.24.0
+ @vue/cli-plugin-babel@3.7.0
+ @vue/cli-plugin-eslint@3.7.0
+ node-sass@4.12.0
+ vue-js-modal@1.3.31
+ @vue/cli-service@3.7.0
+ vuex@3.1.0
+ vue-template-compiler@2.6.10
+ vue-router@3.0.6
+ vue@2.6.10
+ firebase@5.11.1
added 151 packages from 368 contributors, removed 280 packages, updated 380 packages, moved 33 packages and audited 24396 packages in 53.893s
found 1 vulnerability (1 high)
  run `npm audit fix` to fix them, or `npm audit` for details
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That was&amp;hellip;more output than I expected. Let&amp;rsquo;s break that down.&lt;/p&gt;

&lt;h2 id=&#34;deciphering-update-s-output&#34;&gt;Deciphering update&amp;rsquo;s output&lt;/h2&gt;

&lt;p&gt;The first section of output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;npm WARN deprecated joi@14.3.1: This module has moved and is now available at @hapi/joi. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm WARN deprecated topo@3.0.3: This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm WARN deprecated hoek@6.1.3: This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s telling me that I need to change the &lt;code&gt;joi&lt;/code&gt; dependency to &lt;code&gt;@hapi/joi&lt;/code&gt;, but the &lt;code&gt;joi&lt;/code&gt; doesn&amp;rsquo;t appear anywhere in my &lt;code&gt;package.json&lt;/code&gt; file. The answer is to use the &lt;code&gt;npm ls&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm ls joi
attainment-vue@0.1.0 /home/coldwd/src/github.com/dencold/attainment-web
└─┬ @vue/cli-plugin-babel@3.7.0
  └─┬ @vue/cli-shared-utils@3.7.0
    └── joi@14.3.1 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, the &lt;code&gt;@vue/cli-shared-utils&lt;/code&gt; package depends on &lt;code&gt;joi&lt;/code&gt;, and the &lt;code&gt;@vue/cli-shared-utils&lt;/code&gt; itself is a dependency of &lt;code&gt;@vue/cli-plugin-babel&lt;/code&gt;. We can see this captured in the &lt;code&gt;package-lock.json&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;    &amp;quot;@vue/cli-shared-utils&amp;quot;: {
      &amp;quot;version&amp;quot;: &amp;quot;3.7.0&amp;quot;,
      &amp;quot;resolved&amp;quot;: &amp;quot;https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-3.7.0.tgz&amp;quot;,
      &amp;quot;integrity&amp;quot;: &amp;quot;sha512-+LPDAQ1CE3ci1ADOvNqJMPdqyxgJxOq5HUgGDSKCHwviXF6GtynfljZXiSzgWh5ueMFxJphCfeMsTZqFWwsHVg==&amp;quot;,
      &amp;quot;dev&amp;quot;: true,
      &amp;quot;requires&amp;quot;: {
        &amp;quot;chalk&amp;quot;: &amp;quot;^2.4.1&amp;quot;,
        &amp;quot;execa&amp;quot;: &amp;quot;^1.0.0&amp;quot;,
        &amp;quot;joi&amp;quot;: &amp;quot;^14.3.0&amp;quot;,
        &amp;quot;launch-editor&amp;quot;: &amp;quot;^2.2.1&amp;quot;,
        &amp;quot;lru-cache&amp;quot;: &amp;quot;^5.1.1&amp;quot;,
        &amp;quot;node-ipc&amp;quot;: &amp;quot;^9.1.1&amp;quot;,
        &amp;quot;opn&amp;quot;: &amp;quot;^5.3.0&amp;quot;,
        &amp;quot;ora&amp;quot;: &amp;quot;^3.4.0&amp;quot;,
        &amp;quot;request&amp;quot;: &amp;quot;^2.87.0&amp;quot;,
        &amp;quot;request-promise-native&amp;quot;: &amp;quot;^1.0.7&amp;quot;,
        &amp;quot;semver&amp;quot;: &amp;quot;^6.0.0&amp;quot;,
        &amp;quot;string.prototype.padstart&amp;quot;: &amp;quot;^3.0.0&amp;quot;
      },
      &amp;quot;dependencies&amp;quot;: {
        &amp;quot;semver&amp;quot;: {
          &amp;quot;version&amp;quot;: &amp;quot;6.0.0&amp;quot;,
          &amp;quot;resolved&amp;quot;: &amp;quot;https://registry.npmjs.org/semver/-/semver-6.0.0.tgz&amp;quot;,
          &amp;quot;integrity&amp;quot;: &amp;quot;sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==&amp;quot;,
          &amp;quot;dev&amp;quot;: true
        }
      }
    },
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Buuuuuttttt, where the hell does the root package &lt;code&gt;@vue/cli-plugin-babel&lt;/code&gt; come from, you may be asking yourself. It &lt;strong&gt;also&lt;/strong&gt; wasn&amp;rsquo;t listed in the &lt;code&gt;package.json&lt;/code&gt;. That&amp;rsquo;s because I left out the &lt;code&gt;devDependencies&lt;/code&gt; section of &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;  &amp;quot;devDependencies&amp;quot;: {
    &amp;quot;@vue/cli-plugin-babel&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
    &amp;quot;@vue/cli-plugin-eslint&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
    &amp;quot;@vue/cli-service&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
    &amp;quot;node-sass&amp;quot;: &amp;quot;^4.12.0&amp;quot;,
    &amp;quot;sass-loader&amp;quot;: &amp;quot;^7.0.1&amp;quot;,
    &amp;quot;vue-template-compiler&amp;quot;: &amp;quot;^2.6.10&amp;quot;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, I&amp;rsquo;m getting a warning for a package that is depended by another package that &lt;em&gt;itself&lt;/em&gt; is a dependency for the original package that was actually listed as a project dependency. This is a light version of what craziness in package management commonly known as &lt;a href=&#34;https://en.wikipedia.org/wiki/Dependency_hell&#34;&gt;dependency hell&lt;/a&gt; in js development.&lt;/p&gt;

&lt;p&gt;So, now we&amp;rsquo;ve figured out where these warnings are coming from, what do we do about them? The answer is&amp;hellip;nothing. According to the project maintainers, these are &lt;a href=&#34;https://github.com/vuejs/vue-cli/issues/3925#issuecomment-488564952&#34;&gt;safe to ignore&lt;/a&gt; and are the result of transient dependencies that they don&amp;rsquo;t have control over. ¯\_(ツ)_/¯&lt;/p&gt;

&lt;p&gt;The next bit of output that is &lt;em&gt;actually&lt;/em&gt; helpful is this one:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;+ fuse.js@3.4.4
+ bootstrap@3.4.1
+ moment@2.24.0
+ @vue/cli-plugin-babel@3.7.0
+ @vue/cli-plugin-eslint@3.7.0
+ node-sass@4.12.0
+ vue-js-modal@1.3.31
+ @vue/cli-service@3.7.0
+ vuex@3.1.0
+ vue-template-compiler@2.6.10
+ vue-router@3.0.6
+ vue@2.6.10
+ firebase@5.11.1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are acutal &lt;strong&gt;updates&lt;/strong&gt; that were performed on our dependencies, you&amp;rsquo;ll see that it matches up with what we were expecting, above. For example, that &lt;code&gt;bootstrap&lt;/code&gt; dependency we made a fuss about has indeed been updated to &lt;code&gt;3.4.1&lt;/code&gt;. Awesome.&lt;/p&gt;

&lt;h2 id=&#34;audit-checks&#34;&gt;Audit checks&lt;/h2&gt;

&lt;p&gt;If you were paying close attention, you probably noticed a pretty important note at the end of the output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;found 1 vulnerability (1 high)
  run `npm audit fix` to fix them, or `npm audit` for details
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is important and highlights security vulnerabilities that should be taken care of ASAP. Let&amp;rsquo;s do as the update recommends and run &lt;code&gt;npm audit&lt;/code&gt; and see what&amp;rsquo;s going on here:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm audit
                                                                                
                       === npm audit security report ===                        
                                                                                
┌──────────────────────────────────────────────────────────────────────────────┐
│                                Manual Review                                 │
│            Some vulnerabilities require your attention to resolve            │
│                                                                              │
│         Visit https://go.npm.me/audit-guide for additional guidance          │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Arbitrary File Overwrite                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ tar                                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ &amp;gt;=4.4.2                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ node-sass [dev]                                              │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ node-sass &amp;gt; node-gyp &amp;gt; tar                                   │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://npmjs.com/advisories/803                             │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 1 high severity vulnerability in 24396 scanned packages
  1 vulnerability requires manual review. See the full report for details.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we have a problem with the &lt;code&gt;tar&lt;/code&gt; package, specifically any version before &lt;code&gt;4.4.2&lt;/code&gt;. The audit tool lets us know that &lt;code&gt;tar&lt;/code&gt; is a dependency of &lt;code&gt;node-sass&lt;/code&gt; which is in our devDependencies of our &lt;code&gt;package.json&lt;/code&gt; file. Let&amp;rsquo;s confirm this using the &lt;code&gt;npm ls&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm ls tar
attainment-vue@0.1.0 /home/coldwd/src/github.com/dencold/attainment-web
├─┬ firebase@5.11.1
│ └─┬ @firebase/firestore@1.2.2
│   └─┬ grpc@1.20.0
│     └─┬ node-pre-gyp@0.12.0
│       └── tar@4.4.8 
└─┬ node-sass@4.12.0
  └─┬ node-gyp@3.8.0
    └── tar@2.2.1 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we have dependencies on &lt;code&gt;tar&lt;/code&gt; in two places: &lt;code&gt;firebase&lt;/code&gt; which is already on a version that includes the fix, and &lt;code&gt;node-sass&lt;/code&gt; which mathes what we saw in the audit results. We can also use the &lt;code&gt;npm view&lt;/code&gt; command to check out what the npm registry knows about the offending package:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master
$ npm view node-sass

node-sass@4.12.0 | MIT | deps: 17 | versions: 135
Wrapper around libsass
https://github.com/sass/node-sass

keywords: css, libsass, preprocessor, sass, scss, style

bin: node-sass

dist
.tarball: https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz
.shasum: 0914f531932380114a30cc5fa4fa63233a25f017
.integrity: sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
.unpackedSize: 1.8 MB

dependencies:
async-foreach: ^0.1.3  glob: ^7.0.3           nan: ^2.13.2           stdout-stream: ^1.4.0  
chalk: ^1.1.1          in-publish: ^2.0.0     node-gyp: ^3.8.0       true-case-path: ^1.0.2 
cross-spawn: ^3.0.0    lodash: ^4.17.11       npmlog: ^4.0.0         
gaze: ^1.0.0           meow: ^3.7.0           request: ^2.88.0       
get-stdin: ^4.0.1      mkdirp: ^0.5.1         sass-graph: ^2.2.4     

maintainers:
- am11 &amp;lt;adeelbm@outlook.com&amp;gt;
- andrewnez &amp;lt;andrewnez@gmail.com&amp;gt;
- saperski &amp;lt;npm@saper.info&amp;gt;
- xzyfer &amp;lt;xzyfer@gmail.com&amp;gt;

dist-tags:
beta: 4.11.0    latest: 4.12.0  next: 4.8.3     

published a week ago by xzyfer &amp;lt;xzyfer@gmail.com&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From this, we can see that we are indeed on on the latest version &lt;code&gt;4.12.0&lt;/code&gt;. The output also lists the project&amp;rsquo;s homepage which is on &lt;a href=&#34;https://github.com/sass/node-sass&#34;&gt;github&lt;/a&gt;, checking out it&amp;rsquo;s issues, I found &lt;a href=&#34;https://github.com/sass/node-sass/issues/2625&#34;&gt;issue 2625&lt;/a&gt; which breaks down what the package maintainers are doing to deal with this. They are waiting for &lt;em&gt;their&lt;/em&gt; dependency, &lt;code&gt;node-gyp&lt;/code&gt;, to fix it for them.&lt;/p&gt;

&lt;p&gt;Dependency hell indeed. Ughhhh.&lt;/p&gt;

&lt;h2 id=&#34;checking-up&#34;&gt;Checking up&lt;/h2&gt;

&lt;p&gt;Okay, after all those segues, it might be hard to remember that we did actually run a successful update. What do things look like now? If we run &lt;code&gt;npm outdated&lt;/code&gt; again, here&amp;rsquo;s what the results look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master*
$ npm outdated
Package       Current  Wanted         Latest  Location
bootstrap       3.4.1   3.4.1          4.3.1  attainment-vue
chartist       0.10.1  0.10.1         0.11.0  attainment-vue
vue-datetime    0.7.1   0.7.1  1.0.0-beta.10  attainment-vue
vue-fuse        1.5.2   1.5.2          2.0.2  attainment-vue
vue-moment      3.2.0   3.2.0          4.0.0  attainment-vue
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Exactly as expected, all that&amp;rsquo;s left are the packages that have major updates left. Nice! Running a &lt;code&gt;git status&lt;/code&gt; we see:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master*
$ git status
On branch master
Your branch is up to date with &#39;origin/master&#39;.

Changes not staged for commit:
  (use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to update what will be committed)
  (use &amp;quot;git checkout -- &amp;lt;file&amp;gt;...&amp;quot; to discard changes in working directory)

	modified:   package-lock.json
	modified:   package.json

no changes added to commit (use &amp;quot;git add&amp;quot; and/or &amp;quot;git commit -a&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;hellip;and diffing &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;coldwd at thoreau in ~/src/github.com/dencold/attainment-web on master*
$ git d package.json

 package.json | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/package.json b/package.json
index 6bb946c..3382fba 100644
--- a/package.json
+++ b/package.json
@@ -9,26 +9,26 @@
     &amp;quot;lint&amp;quot;: &amp;quot;vue-cli-service lint&amp;quot;
   },
   &amp;quot;dependencies&amp;quot;: {
-    &amp;quot;bootstrap&amp;quot;: &amp;quot;^3.3.7&amp;quot;,
+    &amp;quot;bootstrap&amp;quot;: &amp;quot;^3.4.1&amp;quot;,
     &amp;quot;chartist&amp;quot;: &amp;quot;^0.10.1&amp;quot;,
-    &amp;quot;firebase&amp;quot;: &amp;quot;^5.5.2&amp;quot;,
-    &amp;quot;fuse.js&amp;quot;: &amp;quot;^3.2.1&amp;quot;,
-    &amp;quot;moment&amp;quot;: &amp;quot;^2.22.2&amp;quot;,
-    &amp;quot;vue&amp;quot;: &amp;quot;^2.5.17&amp;quot;,
+    &amp;quot;firebase&amp;quot;: &amp;quot;^5.11.1&amp;quot;,
+    &amp;quot;fuse.js&amp;quot;: &amp;quot;^3.4.4&amp;quot;,
+    &amp;quot;moment&amp;quot;: &amp;quot;^2.24.0&amp;quot;,
+    &amp;quot;vue&amp;quot;: &amp;quot;^2.6.10&amp;quot;,
     &amp;quot;vue-clickaway&amp;quot;: &amp;quot;^2.2.2&amp;quot;,
     &amp;quot;vue-datetime&amp;quot;: &amp;quot;^0.7.1&amp;quot;,
     &amp;quot;vue-fuse&amp;quot;: &amp;quot;^1.5.2&amp;quot;,
-    &amp;quot;vue-js-modal&amp;quot;: &amp;quot;^1.3.16&amp;quot;,
+    &amp;quot;vue-js-modal&amp;quot;: &amp;quot;^1.3.31&amp;quot;,
     &amp;quot;vue-moment&amp;quot;: &amp;quot;^3.2.0&amp;quot;,
-    &amp;quot;vue-router&amp;quot;: &amp;quot;^3.0.1&amp;quot;,
-    &amp;quot;vuex&amp;quot;: &amp;quot;^3.0.1&amp;quot;
+    &amp;quot;vue-router&amp;quot;: &amp;quot;^3.0.6&amp;quot;,
+    &amp;quot;vuex&amp;quot;: &amp;quot;^3.1.0&amp;quot;
   },
   &amp;quot;devDependencies&amp;quot;: {
-    &amp;quot;@vue/cli-plugin-babel&amp;quot;: &amp;quot;^3.0.4&amp;quot;,
-    &amp;quot;@vue/cli-plugin-eslint&amp;quot;: &amp;quot;^3.0.4&amp;quot;,
-    &amp;quot;@vue/cli-service&amp;quot;: &amp;quot;^3.0.4&amp;quot;,
-    &amp;quot;node-sass&amp;quot;: &amp;quot;^4.9.0&amp;quot;,
+    &amp;quot;@vue/cli-plugin-babel&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
+    &amp;quot;@vue/cli-plugin-eslint&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
+    &amp;quot;@vue/cli-service&amp;quot;: &amp;quot;^3.7.0&amp;quot;,
+    &amp;quot;node-sass&amp;quot;: &amp;quot;^4.12.0&amp;quot;,
     &amp;quot;sass-loader&amp;quot;: &amp;quot;^7.0.1&amp;quot;,
-    &amp;quot;vue-template-compiler&amp;quot;: &amp;quot;^2.5.17&amp;quot;
+    &amp;quot;vue-template-compiler&amp;quot;: &amp;quot;^2.6.10&amp;quot;
   }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see the changes correctly accounted for.&lt;/p&gt;

&lt;h2 id=&#34;so-what-s-the-difference-between-update-and-upgrade&#34;&gt;So&amp;hellip;what&amp;rsquo;s the difference between update and upgrade?&lt;/h2&gt;

&lt;p&gt;Nothing! &lt;code&gt;npm upgrade&lt;/code&gt; is an alias for &lt;code&gt;npm update&lt;/code&gt;. As seen from the help output:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ npm -h update
npm update [-g] [&amp;lt;pkg&amp;gt;...]

aliases: up, upgrade, udpate
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, there is, confusingly enough, an &lt;a href=&#34;https://www.npmjs.com/package/npm-upgrade&#34;&gt;npm-upgrade&lt;/a&gt; which is an indpendent package that gives you an interactive mode, with changelog support.&lt;/p&gt;

&lt;h2 id=&#34;helpful-resources&#34;&gt;Helpful resources&lt;/h2&gt;

&lt;p&gt;I found these articles/posts very helpful in writing up my findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://flaviocopes.com/update-npm-dependencies/&#34;&gt;https://flaviocopes.com/update-npm-dependencies/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stackoverflow.com/questions/36668498/what-is-the-difference-between-npm-update-g-npm-upgrade-g-npm-install&#34;&gt;https://stackoverflow.com/questions/36668498/what-is-the-difference-between-npm-update-g-npm-upgrade-g-npm-install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/learnwithrahul/understanding-npm-dependency-resolution-84a24180901b&#34;&gt;https://medium.com/learnwithrahul/understanding-npm-dependency-resolution-84a24180901b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Photo by Brandon Green on Unsplash&lt;/em&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Introducing Hasper</title>
      <link>https://www.dencold.com/post/2016/hugo-hasper/</link>
      <pubDate>Mon, 14 Nov 2016 08:27:49 -0800</pubDate>
      
      <guid>https://www.dencold.com/post/2016/hugo-hasper/</guid>
      <description>

&lt;p&gt;&lt;a href=&#34;https://github.com/dencold/hasper&#34;&gt;Hasper&lt;/a&gt; is a theme for the static site generator &lt;a href=&#34;https://gohugo.io/&#34;&gt;hugo&lt;/a&gt; that I started hacking primarily for the purposes of serving up content on my own blog &lt;a href=&#34;http://www.dencold.com&#34;&gt;dencold.com&lt;/a&gt;. It sources &lt;em&gt;heavily&lt;/em&gt; from the beautiful &lt;a href=&#34;https://github.com/TryGhost/Casper&#34;&gt;casper&lt;/a&gt; theme by the folks at &lt;a href=&#34;https://ghost.org/&#34;&gt;Ghost&lt;/a&gt;, hence the name: &amp;ldquo;Hasper&amp;rdquo;. If you like the styling of casper and use hugo, Hasper may be just what you are looking for.&lt;/p&gt;

&lt;p&gt;You can get a sense for what the Hasper theme looks like by browsing around this site. Hasper is responsible for the layout and presentation of everything you see. I also run the latest version of the code here. To give you a quick idea of some of the features in Hasper, here are some screen captures with some highlights:&lt;/p&gt;

&lt;h3 id=&#34;hasper-home-page&#34;&gt;Hasper Home Page&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/hasper-home-page.png&#34; alt=&#34;hasper home&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;hasper-post-page&#34;&gt;Hasper Post Page&lt;/h3&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/hasper-post-page.png&#34; alt=&#34;hasper post&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Hasper is open source (MIT licensed) and can be found on github at: &lt;a href=&#34;https://github.com/dencold/hasper&#34;&gt;https://github.com/dencold/hasper&lt;/a&gt;. The README there goes into more detail on how you can install and use Hasper/Hugo for your own personal website.&lt;/p&gt;

&lt;p&gt;I welcome comments and feedback via &lt;a href=&#34;https://github.com/dencold/hasper/issues&#34;&gt;github issues&lt;/a&gt; or &lt;a href=&#34;https://github.com/dencold/hasper/pulls&#34;&gt;pull requests&lt;/a&gt;. Please let me know if you are using the theme and how it can be improved.&lt;/p&gt;

&lt;h3 id=&#34;features&#34;&gt;Features&lt;/h3&gt;

&lt;p&gt;Hapser has a couple of nice features out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple author support via standard hugo metadata&lt;/li&gt;
&lt;li&gt;linking to individual author bio pages&lt;/li&gt;
&lt;li&gt;beautiful cover/banner image support&lt;/li&gt;
&lt;li&gt;configurable sharing buttons for post details&lt;/li&gt;
&lt;li&gt;full support for &lt;a href=&#34;https://highlightjs.org/&#34;&gt;highlightjs&lt;/a&gt; themes&lt;/li&gt;
&lt;li&gt;splash image size user-configurable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I keep a &lt;a href=&#34;https://github.com/dencold/hasper/blob/master/CHANGELOG.md&#34;&gt;CHANGELOG&lt;/a&gt; and use SemVer to help keep users abreast of any changes that may affect them.&lt;/p&gt;

&lt;h3 id=&#34;attribution&#34;&gt;Attribution&lt;/h3&gt;

&lt;p&gt;Hasper was originally &lt;a href=&#34;https://github.com/dencold/hugo-theme-casper&#34;&gt;a fork&lt;/a&gt; of the &lt;a href=&#34;https://github.com/vjeantet/hugo-theme-casper&#34;&gt;hugo-theme-casper&lt;/a&gt;. However, the original author was not responding to &lt;a href=&#34;https://github.com/vjeantet/hugo-theme-casper/pull/41&#34;&gt;pull requests&lt;/a&gt;, and I had several changes I needed, so I decided to create Hasper instead.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dennis Coldwell</title>
      <link>https://www.dencold.com/author/dennis/</link>
      <pubDate>Thu, 08 Sep 2016 21:53:28 -0800</pubDate>
      
      <guid>https://www.dencold.com/author/dennis/</guid>
      <description>

&lt;h1 id=&#34;bio&#34;&gt;Bio&lt;/h1&gt;

&lt;p&gt;Dennis is a software engineer with over 15 years of experience working in multiple industries. He loves living in California and feels lucky to live in a place surrounded by so much natural beauty. In the winter, you&amp;rsquo;ll find him most weekends in the Tahoe Basin skiing at &lt;a href=&#34;http://skihomewood.com/&#34;&gt;Homewood Mountain&lt;/a&gt;, where he volunteers as a member of the &lt;a href=&#34;http://www.nsp.org/&#34;&gt;National Ski Patrol&lt;/a&gt;. During the summer, he&amp;rsquo;s often on his bike &lt;a href=&#34;https://www.strava.com/athletes/dencold&#34;&gt;exploring&lt;/a&gt; the bay area. He is also a volunteer DJ and producer at the mighty &lt;a href=&#34;http://kalx.berkeley.edu/&#34;&gt;90.7 KALX&lt;/a&gt; radio station. He lives in Berkeley with his wife, son, and their pet cat, Mochi.&lt;/p&gt;

&lt;h2 id=&#34;employment-status&#34;&gt;Employment status&lt;/h2&gt;

&lt;p&gt;Dennis is currently available for hire. You can find out more about him through these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.dencold.com/resume/dennis-coldwell.pdf&#34;&gt;Resume&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/dencold&#34;&gt;Github profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.linkedin.com/in/dcold&#34;&gt;LinkedIn profile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/dencold&#34;&gt;Twitter stream&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Migrating to AWS Container Registry</title>
      <link>https://www.dencold.com/post/2016/migrating-to-aws-container-registry/</link>
      <pubDate>Sat, 14 May 2016 11:53:28 -0800</pubDate>
      
      <guid>https://www.dencold.com/post/2016/migrating-to-aws-container-registry/</guid>
      <description>

&lt;p&gt;I use &lt;a href=&#34;https://www.docker.com/&#34;&gt;Docker&lt;/a&gt; to manage deployments for my applications and, up until April of 2016, I was using &lt;a href=&#34;https://hub.docker.com&#34;&gt;Docker Hub&lt;/a&gt; as the registry for all of my images. If you have public images, I recommend this route. However, if you have images that need to be kept private (as I do for my client work) you&amp;rsquo;ll need to pay for the service and it can get &lt;a href=&#34;https://hub.docker.com/account/billing-plans/&#34;&gt;quite pricey&lt;/a&gt; for many repositories. Thankfully, Docker&amp;rsquo;s registry is &lt;a href=&#34;https://github.com/docker/distribution&#34;&gt;open-sourced&lt;/a&gt; and the Docker organization has done a fantastic job of documenting the process to host your own registry. But, if you deploy to AWS, there is an even easier way&amp;hellip;&lt;/p&gt;

&lt;h3 id=&#34;aws-container-registry-announced&#34;&gt;AWS Container Registry announced&lt;/h3&gt;

&lt;p&gt;In December of 2015 AWS &lt;a href=&#34;https://aws.amazon.com/blogs/aws/ec2-container-registry-now-generally-available/&#34;&gt;announced&lt;/a&gt; that their Container Registery (ECR) was generally available (in AWS terms, &amp;ldquo;generally&amp;rdquo; means &amp;ldquo;us-east-1&amp;rdquo;). In March of 2016 they &lt;a href=&#34;https://aws.amazon.com/about-aws/whats-new/2016/03/amazon-ec2-container-registry-available-in-us-west-oregon/&#34;&gt;opened up the service to us-west-2&lt;/a&gt;. This is the region that I deploy my applications on, so I was finally able to make the switch to a managed registry. AWS&amp;rsquo;s &lt;a href=&#34;https://aws.amazon.com/ecr/pricing/&#34;&gt;pricing&lt;/a&gt; for this service is crazy cheap:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/aws-ec2-container-registry-pricing.png&#34; alt=&#34;AWS ECR Pricing&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Obviously, YMMV, but I&amp;rsquo;ve never had these costs add up to more than a dollar, per-month.&lt;/p&gt;

&lt;h3 id=&#34;some-terms&#34;&gt;Some terms&amp;hellip;&lt;/h3&gt;

&lt;p&gt;AWS provisions a registry for you when you create your first ECR repository. If you are asking yourself, &amp;ldquo;wait, what&amp;rsquo;s the difference between a registry and a repository&amp;rdquo; like I was, &lt;a href=&#34;http://stackoverflow.com/questions/34004076/difference-between-docker-registry-and-repository&#34;&gt;this stackoverflow post&lt;/a&gt; is for you. So, the AWS &lt;em&gt;registry&lt;/em&gt; is analagous to Docker Hub and &lt;em&gt;repositories&lt;/em&gt; are how your images (and their tags) are organized within the registry. Here is the list of &lt;a href=&#34;https://hub.docker.com/r/dencold/&#34;&gt;my public repositories&lt;/a&gt; on Docker Hub:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/docker-hub-repositories.png&#34; alt=&#34;Docker Hub Repositories&#34; /&gt;&lt;/p&gt;

&lt;p&gt;If I wanted to migrate all of those over to AWS, I&amp;rsquo;d need to explicitly create a repository for each before making a push to the registry. This is different behavior from Docker Hub, which will automatically create a repository for you the first time you push an image.&lt;/p&gt;

&lt;h3 id=&#34;step-by-step-instructions&#34;&gt;Step-by-step instructions&lt;/h3&gt;

&lt;p&gt;Okay, enough background. Let&amp;rsquo;s get your first repository setup. First, I prefer to do my AWS provisioning using their excellent &lt;a href=&#34;https://aws.amazon.com/cli/&#34;&gt;aws-cli&lt;/a&gt; tool. If you haven&amp;rsquo;t done so already, make sure to &lt;a href=&#34;http://docs.aws.amazon.com/cli/latest/userguide/installing.html&#34;&gt;install the tool&lt;/a&gt; via instructions on their site. Additionally, make sure you&amp;rsquo;ve run the &lt;code&gt;aws configure&lt;/code&gt; command and provided an access key that has admin privilages.&lt;/p&gt;

&lt;p&gt;For this example, I&amp;rsquo;m going to show you how I would take my public &lt;a href=&#34;https://hub.docker.com/r/dencold/pgcli/&#34;&gt;pgcli repository&lt;/a&gt; and bring it over to my private AWS instance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create the registry using the ecr &lt;code&gt;create-repository&lt;/code&gt; subcommand (note that the repository name is set to &amp;ldquo;pgcli&amp;rdquo;, you should change this to be the name of your repository).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;$ aws ecr create-repository --region us-west-2 --repository-name pgcli
{
    &amp;quot;repository&amp;quot;: {
        &amp;quot;registryId&amp;quot;: &amp;quot;000042290000&amp;quot;,
        &amp;quot;repositoryName&amp;quot;: &amp;quot;pgcli&amp;quot;,
        &amp;quot;repositoryArn&amp;quot;: &amp;quot;arn:aws:ecr:us-west-2: 000042290000:repository/pgcli&amp;quot;,
        &amp;quot;repositoryUri&amp;quot;: &amp;quot;000042290000.dkr.ecr.us-west-2.amazonaws.com/pgcli&amp;quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Make special note of the &lt;code&gt;repositoryUri&lt;/code&gt; in the json response. At this point I like to take the hostname and store it in an env variable because it&amp;rsquo;s pretty unwieldy (and sadly, AWS does not currently have a way to CNAME/Alias the host). Make sure to replace &lt;code&gt;000042290000&lt;/code&gt; with your registryId.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ export AWS_ECR_HOST=000042290000.dkr.ecr.us-west-2.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Find out your registry login(note that &lt;code&gt;&amp;lt;base64-encoded-auth&amp;gt;&lt;/code&gt; will be a very long byte sequence).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ aws ecr get-login --region us-west-2
docker login -u AWS -p &amp;lt;base64-encoded-auth&amp;gt; -e none https://000042290000.dkr.ecr.us-west-2.amazonaws.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If that looks okay, you can eval it directly to log yourself in via docker:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ $(aws ecr get-login --region us-west-2)
WARNING: login credentials saved in /Users/coldwd/.docker/config.json
Login Succeeded
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Tag the latest local version of your image with the full AWS repository name (docker requires this for pushes to private registries).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ docker tag dencold/pgcli:latest $AWS_ECR_HOST/pgcli:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Finally, you should be able to now push the image up to the repository on your new registry:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ docker push $AWS_ECR_HOST/pgcli:latest
The push refers to a repository [000042290000.dkr.ecr.us-west-2.amazonaws.com/pgcli]
5f70bf18a086: Layer already exists
15a88e76afed: Layer already exists
97315b41b490: Pushed
c57b1a499184: Layer already exists
cff209dfde52: Layer already exists
5439b1ec108e: Layer already exists
61a73490eb04: Layer already exists
a2e0f03e8793: Layer already exists
65f3b0435c42: Pushed
latest: digest: sha256:63216aaa1cd7aa940cc719ffa8b18cb249567906e7c6ba6baa7b1781d6a9d3fd size: 10312
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You&amp;rsquo;re done! If you login to your AWS console and click on the &amp;ldquo;Repositories&amp;rdquo; section of Amazon ECS, you should see it listed:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/aws-ecr-repositories.png&#34; alt=&#34;AWS Repositories&#34; /&gt;&lt;/p&gt;

&lt;p&gt;If you drill into the detail page by clicking on the repository name you should see that the hash checksum matches the output from our push:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2016/aws-ecr-repositories-detail.png&#34; alt=&#34;AWS Repository Detail&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;pulling-images&#34;&gt;Pulling images&lt;/h3&gt;

&lt;p&gt;You can pull down images from your registry from any host. Only prequisites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Docker is installed.&lt;/li&gt;
&lt;li&gt;aws-cli is installed.&lt;/li&gt;
&lt;li&gt;aws-cli is configured with your access key.&lt;/li&gt;
&lt;li&gt;You&amp;rsquo;ve run docker login via the same &lt;code&gt;$(aws ecr get-login --region us-west-2)&lt;/code&gt; command you ran above.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To pull down that image we pushed in the last step, you&amp;rsquo;d just need to run:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ docker pull 000042290000.dkr.ecr.us-west-2.amazonaws.com/pgcli:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;closing-thoughts&#34;&gt;Closing thoughts&lt;/h3&gt;

&lt;p&gt;One disapointment is that AWS gives you no way to name your registry (e.g. &lt;code&gt;000042290000.dkr.ecr.us-west-2.amazonaws.com&lt;/code&gt;) into something a little friendlier, like &lt;code&gt;registry.yourdomain.com&lt;/code&gt;. Since there is no way to associate your own TLS certificate with the registry, you&amp;rsquo;ll get certificate errors if you try to CNAME the host:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ docker login -u AWS -p REDACTED -e none https://registry.mydomain.com
Error response from daemon: invalid registry endpoint https://registry.mydomain.com/v0/: unable to ping registry endpoint https://registry.mydomain.com/v0/
v2 ping attempt failed with error: Get https://registry.mydomain.com/v2/: x509: certificate is valid for *.dkr.ecr.us-west-2.amazonaws.com, not registry.mydomain.com
v1 ping attempt failed with error: Get https://registry.mydomain.com/v1/_ping: x509: certificate is valid for *.dkr.ecr.us-west-2.amazonaws.com, not registry.mydomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This has been raised on the following &lt;a href=&#34;https://forums.aws.amazon.com/thread.jspa?messageID=697917&amp;amp;#697917&#34;&gt;AWS form post&lt;/a&gt;. Hopefully it is something AWS will support in the future.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Going Nuclear with Git Removal</title>
      <link>https://www.dencold.com/post/2016/complete-git-removal/</link>
      <pubDate>Thu, 18 Feb 2016 21:53:28 -0800</pubDate>
      
      <guid>https://www.dencold.com/post/2016/complete-git-removal/</guid>
      <description>

&lt;p&gt;We recently had a developer commit several large movie files into the git repository. Although this can be reverted with a simple call to &lt;code&gt;git rm&lt;/code&gt;, it doesn&amp;rsquo;t entirely solve the problem. Since git is just tracking snapshots, the mp4 is still in the repository&amp;rsquo;s history. Every time you initiate a &lt;code&gt;git clone&lt;/code&gt;, you will be pulling down that mp4 file. This is unnecessary bloat and should be removed. Here&amp;rsquo;s a guide to completely torch a file from git so that it is as if it never existed in the first place.&lt;/p&gt;

&lt;h2 id=&#34;prep-work&#34;&gt;Prep Work&lt;/h2&gt;

&lt;p&gt;This is going to be a dangerous journey. You are rewriting history and irrevocably deleting data from your repository. Let&amp;rsquo;s make sure to have some appropriate backups.&lt;/p&gt;

&lt;p&gt;First, ensure that you are up to date with your remote:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;&amp;gt; cd ~/my_large_repo
&amp;gt; git pull
Already up-to-date.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you&amp;rsquo;re up to date take a full copy of the repo (this can also be achieved with a call to git clone, but a straight copy will make sure all your git remotes/hooks/etc. are preserved).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;&amp;gt; cp -Rp ~/my_large_repo ~/my_large_repo.backup
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;the-simple-option&#34;&gt;The Simple Option&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, the easy way to remove the files from your filesystem is via a quick call to &lt;code&gt;git rm&lt;/code&gt;. For those who are newer to git, read on. For those who are experienced and just want to fully delete the files, jump to the next section.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s tease this out why git rm doesn&amp;rsquo;t quite do the job. Here&amp;rsquo;s what the filesystem looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ ls -altr videos
total 93768
-rw-r--r--  1 coldwd  staff  20581288 Nov  4 18:08 griffith.webm
-rw-r--r--  1 coldwd  staff  22814007 Nov  4 18:08 griffith.mp4
-rw-r--r--  1 coldwd  staff   2498504 Nov  4 18:08 abstract.webm
-rw-r--r--  1 coldwd  staff   2110649 Nov  4 18:08 abstract.mp4
drwxr-xr-x  8 coldwd  staff       272 Nov  4 18:08 ..
drwxr-xr-x  6 coldwd  staff       204 Nov  4 18:08 .
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Those four files come in at just under 48MB of space on the filesystem. Let&amp;rsquo;s also take note of our entire repository size:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ du -sk my_large_repo/
251356  my_large_repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;251MB. Let&amp;rsquo;s try to chop this down by removing the video files with a call to &lt;code&gt;git rm&lt;/code&gt; and also commit it using &lt;code&gt;git commit&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ git rm -rf videos/*
rm &#39;videos/abstract.mp4&#39;
rm &#39;videos/abstract.webm&#39;
rm &#39;videos/griffith.mp4&#39;
rm &#39;videos/griffith.webm&#39;
$ git commit -m &#39;removing video assets&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How did this affect the repo&amp;rsquo;s size?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ du -sk my_large_repo/
204468  my_large_repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Sweet, that&amp;rsquo;s what we were hoping for, the filesystem has dropped by same amount as the removed videos. We&amp;rsquo;re done here, right? Not quite. Git actually still has a record of these files. All we have to do is checkout the previous SHA to bring the deleted files back to life. Here&amp;rsquo;s what our git history looks like right now:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ git log
commit a5cec74b28e5d0600e83360f3f4dad16df46d3cc
Author: Dennis Coldwell
Date:   Mon Nov 4 17:01:37 2013 -0800

    removing video assets

commit 046ebf0ddf90273090c193a8c18523ed5da1ca75
Author: Dennis Coldwell
Date:   Sun Nov 3 11:55:13 2013 -0800

    another day, another commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s checkout the previous commit and see what happens to our repo.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ git checkout 046ebf0ddf90273090c193a8c18523ed5da1ca75
Previous HEAD position was a5cec74... removing video assets
HEAD is now at 046ebf0... another day, another commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Filesize goes back to 251MB now:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ du -sk my_large_repo/
251356  my_large_repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So those files are still taking up space, even though you removed them.&lt;/p&gt;

&lt;h2 id=&#34;the-nuclear-option&#34;&gt;The Nuclear Option&lt;/h2&gt;

&lt;p&gt;There are a couple of ways to go about a full history deletion in git. The one that I prefer is &lt;code&gt;filter-branch&lt;/code&gt;. The &lt;a href=&#34;http://git-scm.com/book&#34;&gt;git book&lt;/a&gt; refers to this technique as the &lt;em&gt;nuclear option&lt;/em&gt; for good reason:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is another history-rewriting option that you can use if you need to rewrite a larger number of commits in some scriptable way — for instance, changing your e-mail address globally or removing a file from every commit. The command is filter-branch, and it can rewrite huge swaths of your history.&lt;sup class=&#34;footnote-ref&#34; id=&#34;fnref:1&#34;&gt;&lt;a rel=&#34;footnote&#34; href=&#34;#fn:1&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The command is powerful and is meant as a way to apply filters across the entire repository. Let&amp;rsquo;s take a look at the command option syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git filter-branch [--env-filter &amp;lt;command&amp;gt;] [--tree-filter &amp;lt;command&amp;gt;]
        [--index-filter &amp;lt;command&amp;gt;] [--parent-filter &amp;lt;command&amp;gt;]
        [--msg-filter &amp;lt;command&amp;gt;] [--commit-filter &amp;lt;command&amp;gt;]
        [--tag-name-filter &amp;lt;command&amp;gt;] [--subdirectory-filter &amp;lt;directory&amp;gt;]
        [--prune-empty]
        [--original &amp;lt;namespace&amp;gt;] [-d &amp;lt;directory&amp;gt;] [-f | --force]
        [--] [&amp;lt;rev-list options&amp;gt;…]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s a lot of options. Here are the ones that we actually care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--index-filter&lt;/code&gt;: does most of the work. It will rewrite the git index and apply the given command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--prune-empty&lt;/code&gt;: if there are any commits that become empty after applying the filter command, this option will prune the commit and make a cleaner history.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--tag-name-filter&lt;/code&gt;: this option will take care of any tags that exist on your repository. We&amp;rsquo;ll pass the identity command of &lt;code&gt;cat&lt;/code&gt; to this option.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--&lt;/code&gt;: indicates the end of the filter-branch options.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--all&lt;/code&gt;: this will apply the changes to all refs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;removing-from-history&#34;&gt;Removing from history&lt;/h3&gt;

&lt;p&gt;Now here&amp;rsquo;s the command that will blow that sucker away from your git repo, &lt;strong&gt;forever&lt;/strong&gt;!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git filter-branch \
    --index-filter &amp;quot;git rm --cached -f --ignore-unmatch videos/abstract.mp4 videos/abstract.webm videos/griffith.mp4 videos/griffith.webm&amp;quot; \
    --prune-empty --tag-name-filter cat -- --all
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt; It&amp;rsquo;s really important to give the full path to the files that you want to delete. The first time I ran filter-branch, I just gave the filenames, but git won&amp;rsquo;t find a match and no changes will be made to your repository.&lt;/p&gt;

&lt;p&gt;When you execute the command git will process &lt;em&gt;every&lt;/em&gt; commit from the very first one made on your repository. You should see output like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;Rewrite aca02f66208ab310a30ac1bad747c44e8e8edbcf (277/403)rm &#39;videos/griffith.mp4&#39;
rm &#39;videos/griffith.webm&#39;
Rewrite ae0a6f00bcaa995946365486792ee5aa046f3293 (278/403)rm &#39;videos/griffith.mp4&#39;
rm &#39;videos/griffith.webm&#39;
Rewrite 2dde79b5bc88a0416a3d17c0879186993911ef86 (279/403)rm &#39;videos/abstract.mp4&#39;
rm &#39;videos/abstract.webm&#39;
rm &#39;videos/griffith.mp4&#39;
rm &#39;videos/griffith.webm&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This tells us a couple of interesting things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first time one of these videos hit the repository was commit #277 (SHA: aca02f662).&lt;/li&gt;
&lt;li&gt;The abstract videos didn&amp;rsquo;t come into being until two commits later.&lt;/li&gt;
&lt;li&gt;Git figures this out and only rewrites the files that match for each commit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once everything is finished, let&amp;rsquo;s review the log again:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ git log
commit 39c68f216b073e33220fdc6d658c16cad2999782
Author: Dennis Coldwell
Date:   Sun Nov 3 11:55:13 2013 -0800

    another day, another commit

commit 0b76a5e6081a75305f23675d04e561bc7bb31e85
Author: Dennis Coldwell
Date:   Sat Nov 2 17:27:53 2013 -0700

    work, work
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Interesting! My original &lt;code&gt;git rm&lt;/code&gt; commit a5cec74b28e5d0600e83360f3f4dad16df46d3cc is completely gone. Further, the prior commit 046ebf0ddf90273090c193a8c18523ed5da1ca75 has now been reset to 39c68f216b073e33220fdc6d658c16cad2999782. In fact &lt;em&gt;every&lt;/em&gt; commit &lt;strong&gt;after&lt;/strong&gt; the first time one of these videos hit the repository has been reindexed (commit #277/aca02f66208ab310a30ac1bad747c44e8e8edbcf).&lt;/p&gt;

&lt;p&gt;This is exactly what we were hoping to have happen. But&amp;hellip;the filesize hasn&amp;rsquo;t dropped as dramatically as we may have hoped:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;du -sk my_large_repo/
207192  my_large_repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is because the objects will still exist in the local repository until they&amp;rsquo;ve been dereferenced/garbage collected. Github has a &lt;a href=&#34;https://help.github.com/articles/remove-sensitive-data#cleanup-and-reclaiming-space&#34;&gt;handy reference&lt;/a&gt; on cleaning up and reclaiming space. Here&amp;rsquo;s a summary from that post:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
# Counting objects: 2437, done.
# Delta compression using up to 4 threads.
# Compressing objects: 100% (1378/1378), done.
# Writing objects: 100% (2437/2437), done.
# Total 2437 (delta 1461), reused 1802 (delta 1048)

$ git gc --aggressive --prune=now
# Counting objects: 2437, done.
# Delta compression using up to 4 threads.
# Compressing objects: 100% (2426/2426), done.
# Writing objects: 100% (2437/2437), done.
# Total 2437 (delta 1483), reused 0 (delta 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does the filesystem look like now?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ du -sk my_large_repo/
117004  my_large_repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;MUCH&lt;/strong&gt; better! We&amp;rsquo;ve dropped the overall repo size by more than half. We are in much better shape than just having run a &lt;code&gt;git rm&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;some-helpful-links&#34;&gt;Some Helpful Links&lt;/h2&gt;

&lt;p&gt;I made use of help from the following posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://help.github.com/articles/remove-sensitive-data&#34;&gt;https://help.github.com/articles/remove-sensitive-data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://stackoverflow.com/questions/2100907/how-do-i-purge-a-huge-file-from-commits-in-git-history&#34;&gt;http://stackoverflow.com/questions/2100907/how-do-i-purge-a-huge-file-from-commits-in-git-history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch&#34;&gt;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;footnotes&#34;&gt;

&lt;hr /&gt;

&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;&lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch&#34;&gt;https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch&lt;/a&gt;
 &lt;a class=&#34;footnote-return&#34; href=&#34;#fnref:1&#34;&gt;&lt;sup&gt;[return]&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Django Caching with Redis</title>
      <link>https://www.dencold.com/post/2014/django-caching-with-redis/</link>
      <pubDate>Wed, 08 Jan 2014 16:18:29 -0800</pubDate>
      
      <guid>https://www.dencold.com/post/2014/django-caching-with-redis/</guid>
      <description>

&lt;p&gt;Django has a pretty good &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/cache/&#34;&gt;documentation page&lt;/a&gt; for enabling caching on the framework. It gives an overview of why caches are a good idea, when to use them, and the various configuration options to make your backend play nice with Django. However, of the four backends mentioned in the docs (memcached, database, filesystem, local-memory), Redis is not listed as an option. This is surprising as Redis is a key-value store that works very well as a cache server and &lt;a href=&#34;http://oldblog.antirez.com/post/redis-memcached-benchmark.html&#34;&gt;compares favorably to memcached&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a little guide to get up and running with Redis to remedy this omission on the django docs.&lt;/p&gt;

&lt;h2 id=&#34;redis-features&#34;&gt;Redis Features&lt;/h2&gt;

&lt;p&gt;Redis also has a lot of features that memcached is lacking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://redis.io/topics/persistence&#34;&gt;persistence&lt;/a&gt;: Redis has persistence configured by default. If your cache server gets restarted, you don&amp;rsquo;t lose all of your data.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://redis.io/topics/data-types&#34;&gt;robust data structures&lt;/a&gt;: memcached can only handle strings &amp;amp; serialized objects. Redis has strings, sets, lists, hashes, and sorted sets.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://redis.io/topics/replication&#34;&gt;replication&lt;/a&gt;: it&amp;rsquo;s a one line configuration setting to enable master-slave replication in Redis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;installing-redis&#34;&gt;Installing Redis&lt;/h2&gt;

&lt;p&gt;You&amp;rsquo;ll first want to install Redis on your local machine, I&amp;rsquo;m on a Mac, so I&amp;rsquo;ve included notes on how to setup your system with OS X. You can also find the &lt;a href=&#34;http://redis.io/download&#34;&gt;installation instructions&lt;/a&gt; directly on the Redis website if you are on another OS.&lt;/p&gt;

&lt;p&gt;If your machine is on Mac OS X 10.9 (Mavericks), make sure to install xcode developer tools so you have access to gcc. Luckily, Apple has made this easy and can be installed with a one-liner from the command line:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ xcode-select --install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you are on an older OS X version, refer to &lt;a href=&#34;http://stackoverflow.com/questions/9353444/how-to-use-install-gcc-on-mac-os-x-10-8-xcode-4-4&#34;&gt;this Stack Overflow post&lt;/a&gt; to get developer tools installed. Once that&amp;rsquo;s squared away, here are the steps to install Redis 2.8.3 (latest stable release as of this post):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ mkdir -p ~/sysinfra/redis
$ cd ~/sysinfra/redis
$ curl -O http://download.redis.io/releases/redis-2.8.3.tar.gz
$ tar xzf redis-2.8.3.tar.gz
$ cd redis-2.8.3
$ make
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;rsquo;ll see a lot of compiler output. After it finishes, it recommends you to run &lt;code&gt;make test&lt;/code&gt; to ensure that the install was successful. Let&amp;rsquo;s do that, but make sure to do this with &lt;code&gt;sudo&lt;/code&gt; as you&amp;rsquo;ll get errors when Redis tries to check for memory leaks on separate processes. Here&amp;rsquo;s the command:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ sudo make test
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If everything worked, you&amp;rsquo;ll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2014/redis_make_test.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;If so, you&amp;rsquo;re good to go! Let&amp;rsquo;s get the Redis server up and running:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ src/redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which should look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2014/redis_running.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Props to &lt;a href=&#34;http://antirez.com/&#34;&gt;antirez&lt;/a&gt; for the awesome use of ascii art. Also, a note that in a production environment, we&amp;rsquo;d want to use a process control system (like &lt;a href=&#34;http://supervisord.org/&#34;&gt;supervisor&lt;/a&gt;) and not run the server in the foreground. For the purposes of learning, it will be helpful to monitor what is going on with the server.&lt;/p&gt;

&lt;h2 id=&#34;django-bindings&#34;&gt;Django bindings&lt;/h2&gt;

&lt;p&gt;Redis is installed, running, and ready to cache stuff. But how do we get our django application to communicate with the Redis server? If you look into the official django docs, you&amp;rsquo;ll see a full &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/cache/#memcached&#34;&gt;writeup for memcached&lt;/a&gt;, here&amp;rsquo;s what that setup looks like in your &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;CACHES = {
    &#39;default&#39;: {
        &#39;BACKEND&#39;: &#39;django.core.cache.backends.memcached.MemcachedCache&#39;,
        &#39;LOCATION&#39;: &#39;127.0.0.1:11211&#39;,
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is super straightforward. We just choose the memchached backend that is included in django&amp;rsquo;s core package and specify a location that the memcached server is running. With Redis, we&amp;rsquo;ll need to first install the backend bindings and then configure the cache in a similar manner.&lt;/p&gt;

&lt;h3 id=&#34;the-paradox-of-choice&#34;&gt;The paradox of choice&lt;/h3&gt;

&lt;p&gt;The two major projects that provide Redis bindings to django are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/niwibe/django-redis&#34;&gt;https://github.com/niwibe/django-redis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sebleier/django-redis-cache&#34;&gt;https://github.com/sebleier/django-redis-cache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can be a little hard to distinguish between the two libraries. They both have similar github metrics:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2014/django-redis-stargazers.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;vs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2014/django-redis-cache-stargazers.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Not sure which to choose, I decided to conduct a &amp;ldquo;scientific&amp;rdquo; poll on the #django IRC channel, here are the results:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://www.dencold.com/images/content/2014/django_irc_redis.png&#34; alt=&#34;&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Pretty inconclusive. Digging deeper, it turns out that &lt;code&gt;django-redis&lt;/code&gt; actually began as a fork of &lt;code&gt;django-redis-cache&lt;/code&gt;. If you dig into the &lt;a href=&#34;https://github.com/niwibe/django-redis&#34;&gt;source code&lt;/a&gt; you&amp;rsquo;ll see that a lot of the core classes are still very similar. Also, &lt;code&gt;django-redis&lt;/code&gt; still installs to the same &amp;ldquo;redis_cache&amp;rdquo; namespace as &lt;code&gt;django-redis-cache&lt;/code&gt;. This means if you were ever to install both packages, you&amp;rsquo;d end up with a namespace clash. This has been &lt;a href=&#34;https://github.com/niwibe/django-redis/issues/45&#34;&gt;raised as an issue&lt;/a&gt; and the author has acknowledged the problem.&lt;/p&gt;

&lt;p&gt;My recommendation is to go with &lt;code&gt;django-redis-cache&lt;/code&gt;. It is the original library and has more community involvement. Additionally, there are contributions on the repository from &lt;a href=&#34;https://github.com/jezdez&#34;&gt;jezdez&lt;/a&gt; and &lt;a href=&#34;https://github.com/carljm&#34;&gt;carljm&lt;/a&gt;, two devs I highly respect.&lt;/p&gt;

&lt;h3 id=&#34;installation&#34;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Use pip to install the package (preferably into a virtualenv):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ pip install django-redis-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will automatically pull and install the &lt;a href=&#34;https://github.com/andymccurdy/redis-py&#34;&gt;redis python package&lt;/a&gt; as it is a dependency.&lt;/p&gt;

&lt;p&gt;While you&amp;rsquo;re at it, you should also install the &lt;a href=&#34;https://github.com/pietern/hiredis-py&#34;&gt;hiredis parser&lt;/a&gt;. This is the most efficient library for parsing the data coming back from the Redis server.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ pip install hiredis
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;re now ready to configure django to use Redis. As a simple configuration you can  add this to your &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;CACHES = {
    &#39;default&#39;: {
        &#39;BACKEND&#39;: &#39;redis_cache.RedisCache&#39;,
        &#39;LOCATION&#39;: &#39;127.0.0.1:6379&#39;,
        &#39;OPTIONS&#39;: {
            &#39;DB&#39;: 0,
            &#39;PASSWORD&#39;: &#39;&#39;,
            &#39;PARSER_CLASS&#39;: &#39;redis.connection.HiredisParser&#39;
        },
    },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s quickly break that down. The django-redis-cache package installs under the &amp;ldquo;redis_cache&amp;rdquo; namespace. Here, we are setting up our &amp;ldquo;default&amp;rdquo; cache to use our django-redis-cache backend, and the server is located on localhost at 127.0.0.1:6379. Redis allows for multiple databases per server and defines this with a zero-based numeric index. The Redis default database is always 0, and we are setting our configuration to match that with &lt;code&gt;&#39;DB&#39;: 0&lt;/code&gt;. We didn&amp;rsquo;t set a password on the Redis server so we keep that configured as an empty string.&lt;/p&gt;

&lt;h2 id=&#34;testing-the-cache&#34;&gt;Testing the cache&lt;/h2&gt;

&lt;p&gt;Now that we have the Redis server running and django is configured to talk to it. Let&amp;rsquo;s test this out and set some cache values. To do this, let&amp;rsquo;s use the django &lt;code&gt;shell&lt;/code&gt; management command.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ cd to/your/django/project
$ python manage.py shell
Python 2.7.5 (default, Nov  6 2013, 00:00:21)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type &amp;quot;help&amp;quot;, &amp;quot;copyright&amp;quot;, &amp;quot;credits&amp;quot; or &amp;quot;license&amp;quot; for more information.
(InteractiveConsole)
&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here we should be able to set some items to cache:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; from django.core.cache import cache
&amp;gt;&amp;gt;&amp;gt; cache.set(&#39;life_universe_everything&#39;, &#39;42&#39;)
True
&amp;gt;&amp;gt;&amp;gt; cache.get(&#39;life_universe_everything&#39;)
&#39;42&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The default TTL for django cache items is 300 seconds. So if you wait five minutes and try to get our value from the cache again. Here&amp;rsquo;s what happens:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; cache.get(&#39;life_universe_everything&#39;)
&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The cache has expired and the backend returns &lt;code&gt;None&lt;/code&gt;. You can change the TTL by passing an optional &lt;em&gt;timeout&lt;/em&gt; to the set method like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; cache.set(&#39;life_universe_everything&#39;, &#39;42&#39;, 3600)
True
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That call would cache the &amp;ldquo;life_universe_everything&amp;rdquo; key for 3600 seconds &amp;ndash; one hour.&lt;/p&gt;

&lt;h2 id=&#34;closing-it-out&#34;&gt;Closing it out&lt;/h2&gt;

&lt;p&gt;That&amp;rsquo;s pretty much all you need to get started with Redis and django. You can now cache expensive calculations very easily in your view/model code. This can have a major impact to the response times on your site.&lt;/p&gt;

&lt;p&gt;This post has focused mostly on getting a Redis server up and functional, but it has  only scratched the surface of what you can do with the cache. The testing examples above use the &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/cache/#the-low-level-cache-api&#34;&gt;low level cache API&lt;/a&gt;. However, you can also make use of &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/cache/#the-per-site-cache&#34;&gt;full site caching&lt;/a&gt;, &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/cache/#the-per-view-cache&#34;&gt;per-view caching&lt;/a&gt;, and &lt;a href=&#34;https://docs.djangoproject.com/en/dev/topics/http/sessions/#using-cached-sessions&#34;&gt;cached sessions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you are really curious on how the cache is implemented, you can read my post analyzing cache records.&lt;/p&gt;

&lt;p&gt;Happy caching!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://stackoverflow.com/questions/7669508/how-can-i-test-if-my-redis-cache-is-working&#34;&gt;http://stackoverflow.com/questions/7669508/how-can-i-test-if-my-redis-cache-is-working&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/martinrusev/django-redis-sessions&#34;&gt;https://github.com/martinrusev/django-redis-sessions&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>The End of Object Inheritance</title>
      <link>https://www.dencold.com/post/2013/end-of-inheritance-pycon2013/</link>
      <pubDate>Mon, 18 Mar 2013 21:53:28 -0800</pubDate>
      
      <guid>https://www.dencold.com/post/2013/end-of-inheritance-pycon2013/</guid>
      <description>

&lt;p&gt;Here are my notes from the PyCon2013 talk given by Augie Fackler &amp;amp; Nathaniel Manista titled &lt;a href=&#34;http://www.youtube.com/watch?v=3MNVP9-hglc&#34;&gt;The End Of Object Inheritance &amp;amp; The Beginning Of A New Modularity&lt;/a&gt;. That link will bring you to a youtube video of the talk.&lt;/p&gt;

&lt;h2 id=&#34;three-premises-for-software&#34;&gt;Three Premises for Software&lt;/h2&gt;

&lt;p&gt;Augie &amp;amp; Nathaniel first discuss three basic concepts that are &amp;ldquo;uncontroversial&amp;rdquo; in software development.&lt;/p&gt;

&lt;h3 id=&#34;use-types-for-nouns&#34;&gt;Use types for nouns&lt;/h3&gt;

&lt;p&gt;When we are talking about data and components that we need in the system, we are using types to refer to them. Nathaniel brings up the differences between a static language like C where the type will be defined at compile-time vs. a dynamic language like Python where we express type in terms of attributes and methods that we rely on from that object.&lt;/p&gt;

&lt;h3 id=&#34;express-ourselves-structurally&#34;&gt;Express ourselves structurally&lt;/h3&gt;

&lt;p&gt;Makes the distinction away from comments which you hardly ever read, or the docstrings which you may read half of the time. Instead, good code should document itself.  For example, we could just throw all our code into a giant module, but instead we break it up into directory structures that make it much more maintainable.&lt;/p&gt;

&lt;h3 id=&#34;most-programming-is-parametric-programming&#34;&gt;Most programming is parametric programming&lt;/h3&gt;

&lt;p&gt;Meaning most programming you do is partial. You are not writing all of the logic in one giant function, rather you are relying on inputs to determine the behavior to take. For functions you have arguments that will change the behavior of the output, for a module you have dependencies specified in your import list.&lt;/p&gt;

&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class MyAbstractBase(object):
    # pretend this is fully implemented
    def orange_method(self):
        ...

    def green_method(self):
        raise NotImplementedError()

    def blue_method(self):
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the client of this class would subclass the base and then provide an implementation for green_method. Something like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class ClientSubclass(MyAbstractBase):
    # we&#39;ve now got a concrete implementation of the green method
    def green_method(self):
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that the client has no reference to blue and orange methods, but it is free to call them. However, what happens if you &lt;em&gt;don&amp;rsquo;t&lt;/em&gt; want the client class to call the orange or blue methods? There really isn&amp;rsquo;t a good solution to hide them from subclasses. People generally rely on comments or docstrings to explain and note that you cannot call certain methods which is kludgy. &amp;ldquo;If you are explaining, even if you&amp;rsquo;re right, you&amp;rsquo;re losing.&amp;rdquo; This is the case with the inheritance based implementation, above. It&amp;rsquo;s technically correct, but you are using that out-of-band documentation channel that many people don&amp;rsquo;t check. In closing, we are violating premises 1 &amp;amp; 2 in order to get to 3.&lt;/p&gt;

&lt;h2 id=&#34;composition&#34;&gt;Composition&lt;/h2&gt;

&lt;p&gt;Everyone has heard of the phrase &amp;ldquo;favor composition over inheritance&amp;rdquo;, it means rather than inheriting you are going to pass one layer into another. It&amp;rsquo;s an explicitly one-way relationship. With inheritance you can have bi-directional communication between the layers, for example, maybe the blue and orange methods have some communication through attributes on self.&lt;/p&gt;

&lt;h3 id=&#34;inhertiance-rewrite&#34;&gt;Inhertiance rewrite&lt;/h3&gt;

&lt;p&gt;Here&amp;rsquo;s how you could use composition to solve the problem above.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class Blue(object):
    def blue_method(self):
        raise NotImplementedError()

class Green(object):
    def green_method(self):
        raise NotImplementedError()

class Orange(object):
    def orange_method(self):
        raise NotImplementedError()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You now have 3 interfaces for the behaviors you are looking to implement. This means that we have given types to every noun we were talking about. Here&amp;rsquo;s how we implement:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;class ImplementedBlue(Blue):
    def blue_method(self):
        ...

class ImplementedGreen(Green):
    def __init__(self, blue):
        self._blue = blue

    def green_method(self):
        ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that now the green implementation has no idea about Orange. It doesn&amp;rsquo;t need it and doesn&amp;rsquo;t care. Instead we inject the blue depency on &lt;strong&gt;init&lt;/strong&gt; and we can use it explicitly.&lt;/p&gt;

&lt;h3 id=&#34;overlapping-interfaces&#34;&gt;Overlapping interfaces&lt;/h3&gt;

&lt;p&gt;Augie makes the point that one of the nice things about inheritance is that you can share method definitions between things very easily. You can define one method that you&amp;rsquo;ll get &amp;ldquo;for free&amp;rdquo; to all derived subclasses. However, readability really suffers in this case. Say you have a method that is defined in the the AbstractBaseClass, then overrided in a subclass (but with a call to super to get the base class functionality) that you are using in your implementation. You have to look at that subclass&amp;rsquo;s implementation, then go up the MRO to figure out the base implementation. If you have multiple inheritance in effect, it&amp;rsquo;s a lot of work just to figure out what the full implementation looks like.&lt;/p&gt;

&lt;p&gt;Delegation, on the other hand, is very simple. You define a one-line function that states that you need a resource &amp;ldquo;green&amp;rdquo; that access the &amp;ldquo;foo&amp;rdquo; attribute and return it, is &lt;em&gt;much&lt;/em&gt; clearer. You don&amp;rsquo;t have to manually traverse what the interpretter is going to figure out for you at runtime as we do in the inheritance example.&lt;/p&gt;

&lt;h2 id=&#34;fault-in-tolerance&#34;&gt;Fault (In)Tolerance&lt;/h2&gt;

&lt;p&gt;In software architecture it is very important to have fault intolerance. We want things to fail as soon as possible and to let us know that we are doing wrong. Allowing an error to fail silently is a &amp;ldquo;bad thing&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Object inhertiance fails at fault tolerance. What happens if an extending class calls a method that it&amp;rsquo;s not supposed to? You could have silent state corruption if the class stores mutable state. Nathaniel brought up a really good example of having perfect behavior for years if, for example, you have a base class that reserves the right to call a function, but doesn&amp;rsquo;t until a future version. Maybe you have an inherited method that finds all occurances of a word in self.file (initialized by the base class, of course) and then deletes the file. Your concrete implementation was calling because it wanted that behavior, but then a future version changes that behavior and the base class calls it directly. That file is now deleted and your implementation is broken, without you having changed any of your code! With dependency injection, you wouldn&amp;rsquo;t have that problem as the self.file wouldn&amp;rsquo;t be shared state that both methods are relying on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remember to &amp;ldquo;Make Illegal States Unrepresentable.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Break all bidrectional relationships!&lt;/li&gt;
&lt;li&gt;Use the unix mentality: do one thing and do it well.&lt;/li&gt;
&lt;li&gt;Your constructors will evaporate into factory functions&lt;/li&gt;
&lt;li&gt;Every one of your modules will transform into collections of abstract types and functions that operate on the types.&lt;/li&gt;
&lt;li&gt;You shouldn&amp;rsquo;t be afraid if some of your methods end up being very very powerful.&lt;/li&gt;
&lt;li&gt;Passing around functions, do it! Think of it as an object with only one method.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://www.dencold.com/post/2017/chrome-dev-summit-2017/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>https://www.dencold.com/post/2017/chrome-dev-summit-2017/</guid>
      <description>

&lt;h1 id=&#34;chrome-dev-summit-keynote&#34;&gt;Chrome Dev Summit Keynote&lt;/h1&gt;

&lt;p&gt;MC&amp;rsquo;s monica &amp;amp;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5th year doing the summit&lt;/li&gt;
&lt;li&gt;TIL Downasaur&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Progressive Web Apps
- trivago
- 150% increase in engagement added to homescreen
- Service worker in webkit / edge&lt;/p&gt;

&lt;h2 id=&#34;workbox&#34;&gt;Workbox&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;developers.google.com/ look for Workbox&lt;/li&gt;
&lt;li&gt;has several caching strategies builtin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Https adoption ~63% of all traffic on Chrome&lt;/p&gt;

&lt;p&gt;One-Tap Sign-Up
- developers.google.com/identity
- Signup on mobile device, automatically signs in back on desktop chrome. cross-platform.&lt;/p&gt;

&lt;h2 id=&#34;the-holy-trinity&#34;&gt;The &amp;ldquo;Holy Trinity&amp;rdquo;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;HTML: Web Components no real update, just polymer, yadda yadda&lt;/li&gt;
&lt;li&gt;CSS: Grid&lt;/li&gt;
&lt;li&gt;JS: ECMAScript 2015 fully implemented except for 1 feature (community has decided it was a badidea)&lt;/li&gt;
&lt;li&gt;v8 - Chrome&amp;rsquo;s javascript engine. New version released. 22% faster on Speedometer. 5% faster on top 25 websites. 40% faster on ARES6.&lt;/li&gt;
&lt;li&gt;v8 has support for WASM (WebAssembly). available on ALL browsers (last holdout was IE). So we now have another compilation* target&lt;/li&gt;
&lt;li&gt;All documentation is moving to MDN. Centralizes across webkit, chrome, edge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;dev-tools&#34;&gt;Dev tools&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lighthouse&lt;/li&gt;
&lt;li&gt;Puppeteer (headless chrome instance) - anything that chrome can do puppeteer can do. CHECK THIS OUT!!! trypuppeteer.&lt;/li&gt;
&lt;li&gt;Webpagetest - new version Chrome User Experience Report. try this out as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keynote - underwhelmed. Very polished, not a lot of amazing announcments&lt;/p&gt;

&lt;h2 id=&#34;a-new-bar-for-modern-web-standards&#34;&gt;A New Bar for Modern Web Standards&lt;/h2&gt;

&lt;h3 id=&#34;thao-tran-chris-wilson&#34;&gt;Thao Tran &amp;amp; Chris Wilson&lt;/h3&gt;

&lt;p&gt;Talking about Scuba Diving. Old way pretty terrible data access. Contrast with HighTide. Need to prioritize for user experience. Don&amp;rsquo;t just provide a service.&lt;/p&gt;

&lt;p&gt;Ele.me featured as the Chinese Food &amp;amp; Ordering app. paint in 400ms, fully interactive in 2s. They have 260M users (the same as the entire population of the United States). They are the leader in food ordering. Built out as a PWA.&lt;/p&gt;

&lt;p&gt;Jio (Indian Entertainment).&lt;/p&gt;

&lt;p&gt;Still seems like the same messaging. PWA&amp;rsquo;s we&amp;rsquo;re big in 2G countries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mercado Libre (mercadolibre.com) big app in Brazil/Latin America.&lt;/li&gt;
&lt;li&gt;Petlove.com.br&lt;/li&gt;
&lt;li&gt;Flipkart&lt;/li&gt;
&lt;li&gt;Starbucks PWA - able to pay via barcode. Don&amp;rsquo;t need a network connection.&lt;/li&gt;
&lt;li&gt;m.uber.com - 3s interactive on 2G, 50kb core app&lt;/li&gt;
&lt;li&gt;instagram - offline sync&lt;/li&gt;
&lt;li&gt;ebay (exporing offline) great posterchild for problem with PWA. they aren&amp;rsquo;t investing in using the tech on the main site, instead doing it on ancillary pieces that doesn&amp;rsquo;t mean much.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;asking-permissions&#34;&gt;Asking Permissions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Right now its an ignorable request that pops up at bottom of screen (mobile)&lt;/li&gt;
&lt;li&gt;Moving to a modal dialog to force Block/Allow&lt;/li&gt;
&lt;li&gt;dc - not sure this helps at all. We really need a better way to present context&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;west-elm&#34;&gt;West Elm&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;November 2016 Launch West Elm beta&lt;/li&gt;
&lt;li&gt;March 2017 good feedback&lt;/li&gt;
&lt;li&gt;May 2017 rollout to 10% traffic&lt;/li&gt;
&lt;li&gt;June 2017 - rebuild with webcomponents&lt;/li&gt;
&lt;li&gt;Rollout to 25% of traffic across ios and android&lt;/li&gt;
&lt;li&gt;October 2017 Pottery Barn/WilliamsSonoma/West Elm retooling to new version&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;building&#34;&gt;Building&lt;/h2&gt;

&lt;h3 id=&#34;owen-campbell-moore&#34;&gt;Owen Campbell-Moore&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;good talk!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wanted to make a cross-platform messaging app. Went from Mobile Chrome Apps -&amp;gt; Cordova -&amp;gt; Java extensions. Ended up with an app that was no longer cross-platform, and was super hacky.&lt;/p&gt;

&lt;p&gt;Installing to home screen: launched to 100% on Android.&lt;/p&gt;

&lt;p&gt;New image upload dialog. Really bad before.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image Chooser (all we need to do is have input tag with type=&amp;ldquo;file&amp;rdquo; accept=&amp;ldquo;image/*&amp;rdquo; and you&amp;rsquo;ll get it for free.&lt;/li&gt;
&lt;li&gt;Image Capture API&lt;/li&gt;
&lt;li&gt;Background Sync API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One tap signup/signin. Cross browser and pretty awesome.&lt;/p&gt;

&lt;h2 id=&#34;faster-talk&#34;&gt;Faster Talk&lt;/h2&gt;

&lt;h3 id=&#34;addy&#34;&gt;Addy&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Evolving RAIL&lt;/li&gt;
&lt;li&gt;Switching to User-happiness (First Paint, First Meaningful, First interactive)&lt;/li&gt;
&lt;li&gt;Parsing javascript is expensive&lt;/li&gt;
&lt;li&gt;PRPL&lt;/li&gt;
&lt;li&gt;5s time to full interactive is our time budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good tools to check out how your app is doing:
- Calibre
- Speedcurve
- BundleSize
- beta.httparchive&lt;/p&gt;

&lt;p&gt;State of the web on mobile&lt;/p&gt;

&lt;p&gt;Chrome User Experience Report
- available as a Big Query result set
- requires signing up for Google Cloud Platform :(
- Lookup origin for yelp!&lt;/p&gt;

&lt;p&gt;Take advantage of &amp;ldquo;fetch&amp;rdquo; and &amp;ldquo;preload&amp;rdquo; apis for handling slow network&lt;/p&gt;

&lt;p&gt;Announcing two new members of the PWA family:
- Pinterest
- Tinder&lt;/p&gt;

&lt;p&gt;dc side note - a lot of the PWA &amp;ldquo;wins&amp;rdquo; are comparing the cost of building the experience. E.g. 56MB for Mobile App on iOS vs. 250kb on PWA. Seems a bit disengenious to me.&lt;/p&gt;

&lt;p&gt;Route-based code-splitting works! Something we might want to do at Yelp.&lt;/p&gt;

&lt;h2 id=&#34;service-worker-workbox&#34;&gt;Service worker / Workbox&lt;/h2&gt;

&lt;p&gt;###&lt;/p&gt;

&lt;p&gt;Using Workbox to make ServiceWorker configuration a lot easier.&lt;/p&gt;

&lt;p&gt;workboxSW.strategies.staleWhileRevalidate&lt;/p&gt;

&lt;h1 id=&#34;chrome-dev-summit-day-2&#34;&gt;Chrome Dev Summit - Day 2&lt;/h1&gt;

&lt;p&gt;&lt;ruby&gt; tag gives superscripts!
&lt;ruby&gt; blah blah blah &lt;rt&gt; howdy &lt;/rt&gt; &lt;/ruby&gt;&lt;/p&gt;

&lt;h2 id=&#34;tooling&#34;&gt;Tooling&lt;/h2&gt;

&lt;h3 id=&#34;paul-irish-eric-bidelman&#34;&gt;Paul Irish / Eric Bidelman&lt;/h3&gt;

&lt;h4 id=&#34;devtools-changes&#34;&gt;DevTools changes&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Local caching for dev tool changes (overrides)&lt;/li&gt;
&lt;li&gt;Performance Monitor - live realtime views of CPU/Memory/etc.&lt;/li&gt;
&lt;li&gt;New Filter Sidebar on the the Console&lt;/li&gt;
&lt;li&gt;Put &amp;ldquo;await&amp;rdquo; in front of any async call that returns a promise, have it resolve for you&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;headless-chrome-puppeteer&#34;&gt;Headless Chrome &amp;amp; Puppeteer&lt;/h4&gt;

&lt;p&gt;What is a headless browser? Well there&amp;rsquo;s no UI, invoked from cli.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ndash;remote-debugging-port=9222&lt;/li&gt;
&lt;li&gt;Chrome.launch({port: 92222, chromeFlags: [&amp;lsquo;&amp;ndash;headless&amp;rsquo;]&lt;/li&gt;
&lt;li&gt;Selenium, PhantomJS, etc.&lt;/li&gt;
&lt;li&gt;Testing Headless Chrome Easy: Puppeteer. It&amp;rsquo;s a node.js library&lt;/li&gt;
&lt;li&gt;async/await, ES6 features, also supports Node 6&lt;/li&gt;
&lt;li&gt;Zero config, bundles latest chromium&lt;/li&gt;
&lt;li&gt;Chrome&amp;rsquo;s reference for using devtools&lt;/li&gt;
&lt;li&gt;Super easy to take a screenshot (5 lines of code)&lt;/li&gt;
&lt;li&gt;Easy page metrics embedding&lt;/li&gt;
&lt;li&gt;Has debugging options&lt;/li&gt;
&lt;li&gt;try-puppeteer.appspot.com&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;future-of-performance-on-the-web&#34;&gt;Future of performance on the web&lt;/h2&gt;

&lt;h3 id=&#34;sam-saccone&#34;&gt;Sam Saccone&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Moving into single page granular assets. E.g. page1.js, page2.js, etc. etc.&lt;/li&gt;
&lt;li&gt;TL;DR don&amp;rsquo;t do it. Chrome team tried to do this with moment.js. Unbundling caused an extra 100ms time.&lt;/li&gt;
&lt;li&gt;Lots of stuff were proposals&amp;hellip;not shipped, why even tell us about it?&lt;/li&gt;
&lt;li&gt;Example &amp;ldquo;DOMChangeList&amp;rdquo;
-&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;v8-talk&#34;&gt;V8 Talk&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;22% better and 40% better on two major benchmarks since last year&lt;/li&gt;
&lt;li&gt;Reducing Jank &amp;ndash;&amp;gt; typically due to GC&lt;/li&gt;
&lt;li&gt;V8 team is taking garbage collection off of the main thread&lt;/li&gt;
&lt;li&gt;They leave some small slivers on the main thread, but now moved off and takes advantage of multiple cores&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;real-world-wasm&#34;&gt;Real World WASM&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A new capability for the web&lt;/li&gt;
&lt;li&gt;Compile target for languages used in native apps&lt;/li&gt;
&lt;li&gt;Binary format, safer than JS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;polymer-talk&#34;&gt;Polymer Talk&lt;/h2&gt;

&lt;h3 id=&#34;taylor-savage&#34;&gt;Taylor Savage&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The javascript-industrial-complex: feedback loop that encourages short term gains&lt;/li&gt;
&lt;li&gt;&amp;ldquo;beware the local maximum&amp;rdquo;&lt;/li&gt;
&lt;li&gt;path to a new web platform feature. very slooowwww&amp;hellip;&lt;/li&gt;
&lt;li&gt;spec proposal, implementation, ship, fix, wait for other browsers to catch up&lt;/li&gt;
&lt;li&gt;web components &amp;amp; polymer&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;javascript-frameworks-panel-discussion&#34;&gt;Javascript Frameworks Panel Discussion&lt;/h2&gt;

&lt;h3 id=&#34;moderated-by-addy&#34;&gt;Moderated by Addy&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Anything you are looking forward to&amp;rdquo; DOM Changelist! Moving more code to be executed on WebWorker and off of main thread.&lt;/li&gt;
&lt;li&gt;Observables - Angular uses this a lot. Mutation observer etc., move to platform. Would be way better if we have primitives.&lt;/li&gt;
&lt;li&gt;Moving from callbacks to promises. Being able to pass along an object.&lt;/li&gt;
&lt;li&gt;Changelist + Worker DOM.&lt;/li&gt;
&lt;li&gt;Async append -&amp;gt; build up a tree of DOM and asyncronously append into the dom.&lt;/li&gt;
&lt;li&gt;Andrew Clark: (React) &amp;ldquo;Except for redesigning layout which we can&amp;rsquo;t, but maybe we will&amp;rdquo;. WTF?&lt;/li&gt;
&lt;li&gt;What framework would you use?&lt;/li&gt;
&lt;li&gt;Frameworks&amp;hellip;you only have about 130kb, how much of that 130kb is your framework taking up?&lt;/li&gt;
&lt;li&gt;Looks over at React.&lt;/li&gt;
&lt;li&gt;Showing that there is a million+1 js frameworks, check out the stage presence at the panel discussion
-&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>