WordCamp Chicago 2016

This weekend I’ll be driving down to WordCamp Chicago in my BRZ. It’s about 2 hours total from home to hotel, and I could use a playlist for the drive there and back.

I’ll be in Chicago chatting about the differences between BuddyPress and bbPress, and I’ll probably talk a bit about Prince, too. I’m on stage at 3pm, and I’d love it if you stopped by to say hi. πŸ’œ

Everything is a Variable

I like to say, that the job of a software engineer is to define variables, and honestly I don’t think it’s really much more than this. Everything in life starts off simple, and can end up as complex as you choose for it to be.

This process is traditionally called “architecting” and at one point in my career I was told I was a brilliant architect by someone I later came to admire quite a bit, Andrew Nacin. Whether or not that’s actually true, is irrelevant, because Andy said so and that’s all anyone should need to hear.

For most engineers, their accidental measure of success is how complex of a problem can I solve. This isn’t just true for software, but for all artists, makers, and creators – it’s a form of validating oneself to say you’ve leveled up and accomplished something more challenging than the time before. It’s learning, and evolving, and shaping your mind by enjoying new experiences, and it’s addicting like everything else in this world.

Ultimately, I think the thing that separates a good engineerΒ from a bad engineer, is the ability to take complex ideas &Β relationships, and make them as simple to understand &Β interact with as possible, for as wide of an audience as possible.

In WordPress, this has traditionally meant introducing flexibility in the form of actions and filters, but for the future of WordPress development, this is about to change dramatically.

If you’re not familiar, WordPress developers have been living in a bubble compared to the rest of the PHP world, and this bubble is about to pop in a huge way when the ability to use versions of PHP higher than 5.2 becomes commonplace.

WordPress itself is a largely procedural codebase, meaning it’s relatively flat and simple. This was both by design, and by intention, because earlier versions of PHP had varying degrees of support for increasingly popularΒ programming concepts.Β Future versions of WordPress will inevitably grow increasingly complex, but I for one am planning on sticking my neck out to ensure this happens only with great intention.

Once plugins and themes can (and will) start flexing more PHP muscle, the WordPress world has the potential to become a very scary place to work inside of, and it’s up to all of us to decide where to position the bar when it comes to code complexity and extensibility.

I’ve come across three WordPress based projects recently thatΒ appeared conceptuallyΒ over-architected, re-solving problems in more complex ways than should have ever been required, considering the requirements and because APIs already existed to solve these problems in WordPress core.

I’m omitting the details from this post (we’re working it out, and my intention isn’t to negatively criticize) because I hope get peopleΒ thinking deeply about what reusable code in WordPress has meant and should mean going forward. Here’s my take:

  • Code that others can quickly understand
  • Problems that others may need solving in their own projects
  • The ability to extend, unplug, replace, or override assumptions the code has made
  • Using existing code intended for it’s purpose, and sending upstream improvements if necessary to unblock your progress
  • It needs to be juice’able – shred it, direct it, blend it with any other code, and it will always act predictably

In the way that art mimics life, these rules are generally what I apply to real-life scenarios. If I can own (or build) aΒ tool that solves many problems, and I can loan it out to someone that may need it, and that tool can be extended to suit many unique needs, it’s an obvious win. This might be a power drill, a table saw, a bucket, a car, a WordPress plugin, or just an idea I’ve had about some random life experience that’s worth sharing or blogging about.

If I can have 1 friend that I enjoy everything with, I’ll marry them so I can continue to enjoy everything they have to offer the world.❀

All of us are in different places, at different times, for different reasons, with different intentions and feelings and goals. We all have different experiences that lead us to unique conclusions about how to approach solving problems and addressing concerns and communicating our feelings. If you ask Mother Nature, this is not a bug, it’s a feature.

EachΒ and every moment that passes results in new variables that require defining. What to eat, what to say, what not to say, how to say it, left or right, stop or go, yes or no.Β Engineers have trained their brains to quickly calculate the consequences of these rapid decisions, and we are difficult people to be around because we are 100 steps ahead and trying to think 101 steps backwards at the same time so what we do makes sense to the people around us.

So when I say that everything is a variable, I mean that it’s your responsibility to define the importance of the variables in your life to create a better tomorrow for the people around you. Hack the world, by being patient, and kind, considerate, and lovely. Learn how to recognize when someone needs help defining their own variables in their lives, and teach them how to in a healthy and constructive way.

$var;

 

The end of IPv6

The end of IPv6 will not be our fault, at least not directly.

Indirectly, and in the next 25 years or so, bots will be so ubiquitous to the modern web, that bots will have bots with bots, and they will autonomously be setting up both physical & virtual servers to scale their requests in such a way that will eventually saturate even the IPv6 protocol.

340,282,366,920,938,463,463,374,607,431,768,211,456

This is the number of available addresses in the global IPv6 range. If I’m right, that’s gonna take a lot of bots.

But consider that services like AkismetΒ claim to fight spam at more thanΒ 7.5 million requests per hour, and Gravatar claims to serve more thanΒ 8.6 billion imagesΒ per day,Β and that’s with me only cherry-picking 2 services that help power 25% of the web, amongst a sea of tens of thousands in the remaining 75%.

As services like these start to become increasingly intelligent, their computational needs increase exponentially, and the number of independent services necessary to keep up with those needs will follow suit.

Consider an application like Slack, where upon opening 1 application, it opens close to 20 individual sockets, each acting like a neurological meld between the client application on my Mac and the many servers they no-doubt are wrangling to keep up with the growing number of Slack networks I’m a part of.

When you start to look at the raw numbers, the insane amount of traffic, the ludicrous amount of connections required to make the world wide web of computers interact with each other, IPv6 suddenly starts to look less big than it did originally.

If we round up Gravatar’s numbers to 10 billion images per day, it will only take 100 days to hit 1 trillion (1,000,000,000,000) images. I have no idea how many physical servers (or public IP addresses) it takes to do this, but I bit it’s at least a few. If a few more services the size of (and equally as efficient as) Gravatar are invented, we start to double-up pretty quickly.

And I have a hunch that no service will be as efficient as Gravatar is at doing what it does; anything of this scale will only grow in complexity and necessities.

It may not happen in my lifetime, but make note that if you squint far enough into the not-too-distant future, even IPv6 won’t save the internet for very long.

global__r – errors in logs

If you’re using WordPress Multisite in a highly scalable environment using HyperDB or LudicrousDB, you may have seen global__r errors in your logs.

Can't select global__r... yada yada yada

The “global” part of “global__r” comes from these database drop-ins defaulting to a “global” dataset if nothing is found or explicitly passed in. The “__r” part comes from looking at databases intended for reading — databases designated as slaves (vs. master databases intended for writing “__w”).

So if a SELECT query is failing, why would that be?

The first and most logical reason is that the database is down. Check to make sure it’s not by attempting to communicate with the database directly via whatever you are most comfortable with (command line, SequalPRO, etc…)

The second most logical reason is that your web server (powering the PHP part of your application) is unable to reach your database server. Check to make sure fail2ban or some other firewall utility hasn’t erroneously blocked things, and then try to manually ping & connect the two servers together to ensure you receive a good response.

The final and less obvious reason this will occur, is harder to track down, and I think might be the source of your error log entries if everything else checks out and you’ve made it to this blog post after scouring the web for answers.

There are two queries that run inside of upgrade_network() and populate_options() respectfully, that try to delete all of the transients for a specific site and a specific network. These two queries are unlikely to get caught by the matching regex used to map database table names to what HyperDB or LudicrousDB use to route queries to their respective servers. They look something like this:

DELETE a, b FROM $wpdb->options a, $wpdb->options b

and

DELETE a, b FROM $wpdb->sitemeta a, $wpdb->sitemeta b

If you search all of WordPress, these are the only two places raw queries like this are done, and they’re only ran under specific conditions where WordPress is cleaning up after itself during a database upgrade. This means the conditions are perfect for a surprise entry in your error logs once in a blue moon when you aren’t hand-holding a huge WordPress multisite/multi-network database upgrade.

How do we prevent these, and what’s the repercussion? The solution is probably a regex fix upstream to these plugins and/or WordPress’s WPDB base class to properly match these queries. The repercussion is transients that don’t get deleted, which isn’t usually a huge problem unless it causes the database upgrade to continuously run; if that was the case, you’d have lots of entries in your error logs.

I have a hunch this issue is exacerbated by object caching plugins that store transients in memory and not in the database. In these types of installations, these raw queries are trying to delete data that never would have been there in the first place.

I’ve also been staring at this code back and forth for a few weeks now, and while there are a lot of moving parts, I haven’t identified any data corruption or loss issues, and these queries are properly escaped and prepared, so it’s unlikely HyperDB or LudicrousDB would introduce anything that might be harmful to existing data.

If you have these issues, hopefully this helps you isolate the root cause to identify whether this is a configuration issue, a caching issue, a communication issue, or an issue with the database itself. If you have more info, I’d love to hear about it in the comments below.❀

“The Average Person”

I know you’ve talked about them. I know you’ve criticized them. You’ve both championed andΒ judged them in the same breath. Today, I’m going to talk about the average person.

I’m an average person, and you are too. Don’t forget this.

I’m average at more things than I’m good at, actually. I’m likely average at just about anything I’ve only ever done a handful of times that I didn’t find captivating enough to become above-average at. Go figure.

In software development, we talk a lot about “the average person” as if they require some kind of hand-holding or help. The systems are inherently complex, and the software should ultimately eliminate that complexity for them.

In real life, “the average person” is usually some kind of dumbass whoΒ acts irresponsibly. They don’t change the oil in their car because “the average person” doesn’t know what oil is or how it works or why it’s necessary. They aren’t financially responsible because “the average person” is living check-to-check without savings or investments. Whatever…

In customer service, “the average person” is usually an inconsiderate jerkΒ that takes no responsibility for their own actions because the customer is always right, and all they do is complain about nothing. This one might actually be true. Just kidding. Maybe. I mean, I’m a customer, but I don’t think I’m an average one. Sigh.

In every scenario I can imagine, everyone makes the average person out to be less-than, incompetent, or somehow beneath them, to convey that the person saying it is somehow above the average at this one thing, if not others to justify and support their perspective.

I’m guilty of this. It’s easy to lump people together, classify them for one reason or another, and quickly convey to others the demographic you’re targeting. I think, though, that this simplifies a much larger issue, and is a slippery slope towards introducing a top-down culture where leaders accidentally (vs. intentionally) influence their constituents to think and speak poorly ofΒ those less experienced than they are.

One place I do this constantly, and without joy, is driving a car. I love driving. I’m good at it. I’ve easily logged a over a million miles between 15 cars in my lifetime. Because of my passion and experience level, I have a difficult time having empathy for people that aren’t very good at driving but are out in public trying to do it anyways. My wife and I lament about how many times someone almost kills us on a daily basis, because “the average person” is talking, texting, not paying attention, or totally lacks any kind of spacial awareness to understand the consequences of their driving actions.

It’s a bad way to be, I think.

It’s toxic, and perpetually negative. It creates this reality distortion field between you and other people, that they’re not actually people trying to accomplish the same tasks you are but maybe not doing as good a job at is as you would do. I’m not saying it isn’t true, or that you aren’t actually better than that average Joe; rather, I’m saying that patting yourself on the back for having more experience or higher comprehension is poor form, selfish, and sets bad precedent and example for anyone that witnesses it.

This is why more sophisticated strategists exist, that are able to boil groups of people down not into averages, but into almost literal boxes to which they fit comfortably in. It’s like stereotyping, but in a good way, I guess? People that have this ability are fascinating to me, because after years of working largely alone and remotely I think I’ve lost what little social comfort I earned in my teens and twenties and have in increasingly difficult time being comfortable around people that are above average at something I am average at. Phew…

If you find yourself thinking about “the average person” please don’t forget that you’re probably average at a bunch of stuff, and someone probably thought of you in the context of being totally vanilla and without value when it comes to some dumb thing that you don’t even care about. Try to flip your verbiage around to bring out the best in whatever it is you’re trying to accomplish, and you’ll have more positive results.

And thanks for tolerating my average writing skills!❀

Mother Nature’s Toolbox Must Be Heavy

Running npm install for WordPress is a terrifying experience. It installs so many libraries and dependencies, it would take a lifetime to learn them all. If you’ve never had the pleasure, here’s what it looks like today:

WordPress@4.5.0 /Users/johnjamesjacoby/Work/VVV/www/wordpress-develop
β”œβ”€β”¬ autoprefixer@6.1.2
β”‚ β”œβ”€β”€ browserslist@1.0.1
β”‚ β”œβ”€β”€ caniuse-db@1.0.30000384
β”‚ β”œβ”€β”€ num2fraction@1.2.2
β”‚ β”œβ”€β”¬ postcss@5.0.14
β”‚ β”‚ β”œβ”€β”€ js-base64@2.1.9
β”‚ β”‚ β”œβ”€β”€ source-map@0.5.3
β”‚ β”‚ └─┬ supports-color@3.1.2
β”‚ β”‚   └── has-flag@1.0.0
β”‚ └── postcss-value-parser@3.2.3
β”œβ”€β”¬ grunt@0.4.5
β”‚ β”œβ”€β”€ async@0.1.22
β”‚ β”œβ”€β”€ coffee-script@1.3.3
β”‚ β”œβ”€β”€ colors@0.6.2
β”‚ β”œβ”€β”€ dateformat@1.0.2-1.2.3
β”‚ β”œβ”€β”€ eventemitter2@0.4.14
β”‚ β”œβ”€β”€ exit@0.1.2
β”‚ β”œβ”€β”¬ findup-sync@0.1.3
β”‚ β”‚ β”œβ”€β”¬ glob@3.2.11
β”‚ β”‚ β”‚ └── minimatch@0.3.0
β”‚ β”‚ └── lodash@2.4.2
β”‚ β”œβ”€β”€ getobject@0.1.0
β”‚ β”œβ”€β”¬ glob@3.1.21
β”‚ β”‚ β”œβ”€β”€ graceful-fs@1.2.3
β”‚ β”‚ └── inherits@1.0.2
β”‚ β”œβ”€β”¬ grunt-legacy-log@0.1.3
β”‚ β”‚ β”œβ”€β”¬ grunt-legacy-log-utils@0.1.1
β”‚ β”‚ β”‚ β”œβ”€β”€ lodash@2.4.2
β”‚ β”‚ β”‚ └── underscore.string@2.3.3
β”‚ β”‚ β”œβ”€β”€ lodash@2.4.2
β”‚ β”‚ └── underscore.string@2.3.3
β”‚ β”œβ”€β”€ hooker@0.2.3
β”‚ β”œβ”€β”€ iconv-lite@0.2.11
β”‚ β”œβ”€β”¬ js-yaml@2.0.5
β”‚ β”‚ └─┬ argparse@0.1.16
β”‚ β”‚   β”œβ”€β”€ underscore@1.7.0
β”‚ β”‚   └── underscore.string@2.4.0
β”‚ β”œβ”€β”€ lodash@0.9.2
β”‚ β”œβ”€β”¬ minimatch@0.2.14
β”‚ β”‚ β”œβ”€β”€ lru-cache@2.7.3
β”‚ β”‚ └── sigmund@1.0.1
β”‚ β”œβ”€β”¬ nopt@1.0.10
β”‚ β”‚ └── abbrev@1.0.7
β”‚ β”œβ”€β”€ rimraf@2.2.8
β”‚ β”œβ”€β”€ underscore.string@2.2.1
β”‚ └── which@1.0.9
β”œβ”€β”¬ grunt-browserify@4.0.1
β”‚ β”œβ”€β”€ async@0.9.2
β”‚ β”œβ”€β”¬ browserify@11.2.0
β”‚ β”‚ β”œβ”€β”€ assert@1.3.0
β”‚ β”‚ β”œβ”€β”¬ browser-pack@5.0.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ combine-source-map@0.6.1
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ convert-source-map@1.1.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ inline-source-map@0.5.0
β”‚ β”‚ β”‚ β”‚ β”‚ └── source-map@0.4.4
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ lodash.memoize@3.0.4
β”‚ β”‚ β”‚ β”‚ └── source-map@0.4.4
β”‚ β”‚ β”‚ └── umd@3.0.1
β”‚ β”‚ β”œβ”€β”€ browser-resolve@1.11.0
β”‚ β”‚ β”œβ”€β”¬ browserify-zlib@0.1.4
β”‚ β”‚ β”‚ └── pako@0.2.8
β”‚ β”‚ β”œβ”€β”¬ buffer@3.6.0
β”‚ β”‚ β”‚ β”œβ”€β”€ base64-js@0.0.8
β”‚ β”‚ β”‚ β”œβ”€β”€ ieee754@1.1.6
β”‚ β”‚ β”‚ └── isarray@1.0.0
β”‚ β”‚ β”œβ”€β”€ builtins@0.0.7
β”‚ β”‚ β”œβ”€β”€ commondir@0.0.1
β”‚ β”‚ β”œβ”€β”¬ concat-stream@1.4.10
β”‚ β”‚ β”‚ β”œβ”€β”€ readable-stream@1.1.13
β”‚ β”‚ β”‚ └── typedarray@0.0.6
β”‚ β”‚ β”œβ”€β”¬ console-browserify@1.1.0
β”‚ β”‚ β”‚ └── date-now@0.1.4
β”‚ β”‚ β”œβ”€β”€ constants-browserify@0.0.1
β”‚ β”‚ β”œβ”€β”¬ crypto-browserify@3.11.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ browserify-cipher@1.0.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ browserify-aes@1.0.5
β”‚ β”‚ β”‚ β”‚ β”‚ └── buffer-xor@1.0.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ browserify-des@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ des.js@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚   └── minimalistic-assert@1.0.0
β”‚ β”‚ β”‚ β”‚ └── evp_bytestokey@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ browserify-sign@4.0.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ bn.js@4.6.2
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ browserify-rsa@4.0.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ elliptic@6.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ brorand@1.0.5
β”‚ β”‚ β”‚ β”‚ β”‚ └── hash.js@1.0.3
β”‚ β”‚ β”‚ β”‚ └─┬ parse-asn1@5.0.0
β”‚ β”‚ β”‚ β”‚   └── asn1.js@4.3.0
β”‚ β”‚ β”‚ β”œβ”€β”€ create-ecdh@4.0.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ create-hash@1.1.2
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ cipher-base@1.0.2
β”‚ β”‚ β”‚ β”‚ └── ripemd160@1.0.1
β”‚ β”‚ β”‚ β”œβ”€β”€ create-hmac@1.1.4
β”‚ β”‚ β”‚ β”œβ”€β”¬ diffie-hellman@5.0.0
β”‚ β”‚ β”‚ β”‚ └── miller-rabin@4.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ pbkdf2@3.0.4
β”‚ β”‚ β”‚ β”œβ”€β”€ public-encrypt@4.0.0
β”‚ β”‚ β”‚ └── randombytes@2.0.1
β”‚ β”‚ β”œβ”€β”€ defined@1.0.0
β”‚ β”‚ β”œβ”€β”€ deps-sort@1.3.9
β”‚ β”‚ β”œβ”€β”€ domain-browser@1.1.7
β”‚ β”‚ β”œβ”€β”¬ duplexer2@0.0.2
β”‚ β”‚ β”‚ └── readable-stream@1.1.13
β”‚ β”‚ β”œβ”€β”€ events@1.0.2
β”‚ β”‚ β”œβ”€β”¬ glob@4.5.3
β”‚ β”‚ β”‚ └── minimatch@2.0.10
β”‚ β”‚ β”œβ”€β”¬ has@1.0.1
β”‚ β”‚ β”‚ └── function-bind@1.0.2
β”‚ β”‚ β”œβ”€β”€ htmlescape@1.1.0
β”‚ β”‚ β”œβ”€β”€ https-browserify@0.0.1
β”‚ β”‚ β”œβ”€β”€ inherits@2.0.1
β”‚ β”‚ β”œβ”€β”¬ insert-module-globals@6.6.3
β”‚ β”‚ β”‚ β”œβ”€β”€ is-buffer@1.1.1
β”‚ β”‚ β”‚ └─┬ lexical-scope@1.2.0
β”‚ β”‚ β”‚   └── astw@2.0.0
β”‚ β”‚ β”œβ”€β”€ isarray@0.0.1
β”‚ β”‚ β”œβ”€β”¬ JSONStream@1.0.7
β”‚ β”‚ β”‚ β”œβ”€β”€ jsonparse@1.2.0
β”‚ β”‚ β”‚ └── through@2.3.8
β”‚ β”‚ β”œβ”€β”¬ labeled-stream-splicer@1.0.2
β”‚ β”‚ β”‚ └─┬ stream-splicer@1.3.2
β”‚ β”‚ β”‚   └── readable-stream@1.1.13
β”‚ β”‚ β”œβ”€β”¬ module-deps@3.9.1
β”‚ β”‚ β”‚ β”œβ”€β”€ detective@4.3.1
β”‚ β”‚ β”‚ β”œβ”€β”€ readable-stream@1.1.13
β”‚ β”‚ β”‚ └─┬ stream-combiner2@1.0.2
β”‚ β”‚ β”‚   └─┬ through2@0.5.1
β”‚ β”‚ β”‚     β”œβ”€β”€ readable-stream@1.0.33
β”‚ β”‚ β”‚     └── xtend@3.0.0
β”‚ β”‚ β”œβ”€β”€ os-browserify@0.1.2
β”‚ β”‚ β”œβ”€β”¬ parents@1.0.1
β”‚ β”‚ β”‚ └── path-platform@0.11.15
β”‚ β”‚ β”œβ”€β”€ path-browserify@0.0.0
β”‚ β”‚ β”œβ”€β”€ process@0.11.2
β”‚ β”‚ β”œβ”€β”€ punycode@1.4.0
β”‚ β”‚ β”œβ”€β”€ querystring-es3@0.2.1
β”‚ β”‚ β”œβ”€β”¬ read-only-stream@1.1.1
β”‚ β”‚ β”‚ β”œβ”€β”€ readable-stream@1.1.13
β”‚ β”‚ β”‚ └─┬ readable-wrap@1.0.0
β”‚ β”‚ β”‚   └── readable-stream@1.1.13
β”‚ β”‚ β”œβ”€β”¬ readable-stream@2.0.5
β”‚ β”‚ β”‚ β”œβ”€β”€ core-util-is@1.0.2
β”‚ β”‚ β”‚ β”œβ”€β”€ process-nextick-args@1.0.6
β”‚ β”‚ β”‚ └── util-deprecate@1.0.2
β”‚ β”‚ β”œβ”€β”¬ shasum@1.0.2
β”‚ β”‚ β”‚ β”œβ”€β”¬ json-stable-stringify@0.0.1
β”‚ β”‚ β”‚ β”‚ └── jsonify@0.0.0
β”‚ β”‚ β”‚ └── sha.js@2.4.4
β”‚ β”‚ β”œβ”€β”€ shell-quote@0.0.1
β”‚ β”‚ β”œβ”€β”€ stream-browserify@2.0.1
β”‚ β”‚ β”œβ”€β”¬ stream-http@1.7.1
β”‚ β”‚ β”‚ β”œβ”€β”€ builtin-status-codes@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ foreach@2.0.5
β”‚ β”‚ β”‚ β”œβ”€β”€ indexof@0.0.1
β”‚ β”‚ β”‚ └── object-keys@1.0.9
β”‚ β”‚ β”œβ”€β”€ string_decoder@0.10.31
β”‚ β”‚ β”œβ”€β”¬ subarg@1.0.0
β”‚ β”‚ β”‚ └── minimist@1.2.0
β”‚ β”‚ β”œβ”€β”¬ syntax-error@1.1.4
β”‚ β”‚ β”‚ └── acorn@1.2.2
β”‚ β”‚ β”œβ”€β”¬ through2@1.1.1
β”‚ β”‚ β”‚ └── readable-stream@1.1.13
β”‚ β”‚ β”œβ”€β”€ timers-browserify@1.4.2
β”‚ β”‚ β”œβ”€β”€ tty-browserify@0.0.0
β”‚ β”‚ β”œβ”€β”¬ url@0.10.3
β”‚ β”‚ β”‚ β”œβ”€β”€ punycode@1.3.2
β”‚ β”‚ β”‚ └── querystring@0.2.0
β”‚ β”‚ β”œβ”€β”€ util@0.10.3
β”‚ β”‚ β”œβ”€β”€ vm-browserify@0.0.4
β”‚ β”‚ └── xtend@4.0.1
β”‚ β”œβ”€β”¬ glob@5.0.15
β”‚ β”‚ β”œβ”€β”¬ inflight@1.0.4
β”‚ β”‚ β”‚ └── wrappy@1.0.1
β”‚ β”‚ β”œβ”€β”¬ minimatch@3.0.0
β”‚ β”‚ β”‚ └─┬ brace-expansion@1.1.2
β”‚ β”‚ β”‚   β”œβ”€β”€ balanced-match@0.3.0
β”‚ β”‚ β”‚   └── concat-map@0.0.1
β”‚ β”‚ β”œβ”€β”€ once@1.3.3
β”‚ β”‚ └── path-is-absolute@1.0.0
β”‚ β”œβ”€β”€ lodash@3.10.1
β”‚ β”œβ”€β”€ resolve@1.1.6
β”‚ └─┬ watchify@3.6.1
β”‚   β”œβ”€β”¬ anymatch@1.3.0
β”‚   β”‚ β”œβ”€β”€ arrify@1.0.1
β”‚   β”‚ └─┬ micromatch@2.3.7
β”‚   β”‚   β”œβ”€β”¬ arr-diff@2.0.0
β”‚   β”‚   β”‚ └── arr-flatten@1.0.1
β”‚   β”‚   β”œβ”€β”€ array-unique@0.2.1
β”‚   β”‚   β”œβ”€β”¬ braces@1.8.3
β”‚   β”‚   β”‚ β”œβ”€β”¬ expand-range@1.8.1
β”‚   β”‚   β”‚ β”‚ └─┬ fill-range@2.2.3
β”‚   β”‚   β”‚ β”‚   β”œβ”€β”€ is-number@2.1.0
β”‚   β”‚   β”‚ β”‚   β”œβ”€β”€ isobject@2.0.0
β”‚   β”‚   β”‚ β”‚   β”œβ”€β”€ randomatic@1.1.5
β”‚   β”‚   β”‚ β”‚   └── repeat-string@1.5.2
β”‚   β”‚   β”‚ β”œβ”€β”€ preserve@0.2.0
β”‚   β”‚   β”‚ └── repeat-element@1.1.2
β”‚   β”‚   β”œβ”€β”€ expand-brackets@0.1.4
β”‚   β”‚   β”œβ”€β”¬ extglob@0.3.1
β”‚   β”‚   β”‚ β”œβ”€β”¬ ansi-green@0.1.1
β”‚   β”‚   β”‚ β”‚ └── ansi-wrap@0.1.0
β”‚   β”‚   β”‚ └── success-symbol@0.1.0
β”‚   β”‚   β”œβ”€β”€ filename-regex@2.0.0
β”‚   β”‚   β”œβ”€β”€ is-extglob@1.0.0
β”‚   β”‚   β”œβ”€β”€ kind-of@3.0.2
β”‚   β”‚   β”œβ”€β”€ normalize-path@2.0.1
β”‚   β”‚   β”œβ”€β”¬ object.omit@2.0.0
β”‚   β”‚   β”‚ β”œβ”€β”¬ for-own@0.1.3
β”‚   β”‚   β”‚ β”‚ └── for-in@0.1.4
β”‚   β”‚   β”‚ └── is-extendable@0.1.1
β”‚   β”‚   β”œβ”€β”¬ parse-glob@3.0.4
β”‚   β”‚   β”‚ β”œβ”€β”€ glob-base@0.3.0
β”‚   β”‚   β”‚ └── is-dotfile@1.0.2
β”‚   β”‚   └─┬ regex-cache@0.4.2
β”‚   β”‚     β”œβ”€β”€ is-equal-shallow@0.1.3
β”‚   β”‚     └── is-primitive@2.0.0
β”‚   β”œβ”€β”¬ browserify@12.0.1
β”‚   β”‚ β”œβ”€β”¬ browser-pack@6.0.1
β”‚   β”‚ β”‚ └─┬ combine-source-map@0.7.1
β”‚   β”‚ β”‚   β”œβ”€β”€ inline-source-map@0.6.1
β”‚   β”‚ β”‚   └── source-map@0.4.2
β”‚   β”‚ β”œβ”€β”€ concat-stream@1.5.1
β”‚   β”‚ β”œβ”€β”€ constants-browserify@1.0.0
β”‚   β”‚ β”œβ”€β”€ deps-sort@2.0.0
β”‚   β”‚ β”œβ”€β”€ duplexer2@0.1.4
β”‚   β”‚ β”œβ”€β”€ events@1.1.0
β”‚   β”‚ β”œβ”€β”¬ glob@5.0.15
β”‚   β”‚ β”‚ └── minimatch@3.0.0
β”‚   β”‚ β”œβ”€β”€ insert-module-globals@7.0.1
β”‚   β”‚ β”œβ”€β”¬ labeled-stream-splicer@2.0.0
β”‚   β”‚ β”‚ └── stream-splicer@2.0.0
β”‚   β”‚ β”œβ”€β”¬ module-deps@4.0.5
β”‚   β”‚ β”‚ └── stream-combiner2@1.1.1
β”‚   β”‚ β”œβ”€β”€ read-only-stream@2.0.0
β”‚   β”‚ β”œβ”€β”€ shell-quote@1.4.3
β”‚   β”‚ β”œβ”€β”€ stream-http@2.0.2
β”‚   β”‚ └─┬ url@0.11.0
β”‚   β”‚   └── punycode@1.3.2
β”‚   β”œβ”€β”¬ chokidar@1.4.2
β”‚   β”‚ β”œβ”€β”€ async-each@0.1.6
β”‚   β”‚ β”œβ”€β”¬ fsevents@1.0.6
β”‚   β”‚ β”‚ └─┬ node-pre-gyp@0.6.17
β”‚   β”‚ β”‚   β”œβ”€β”¬ mkdirp@0.5.1
β”‚   β”‚ β”‚   β”‚ └── minimist@0.0.8
β”‚   β”‚ β”‚   β”œβ”€β”¬ nopt@3.0.6
β”‚   β”‚ β”‚   β”‚ └── abbrev@1.0.7
β”‚   β”‚ β”‚   β”œβ”€β”¬ npmlog@2.0.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ ansi@0.3.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ are-we-there-yet@1.0.4
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ delegates@0.1.0
β”‚   β”‚ β”‚   β”‚ β”‚ └─┬ readable-stream@1.1.13
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ core-util-is@1.0.2
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ isarray@0.0.1
β”‚   β”‚ β”‚   β”‚ β”‚   └── string_decoder@0.10.31
β”‚   β”‚ β”‚   β”‚ └─┬ gauge@1.2.2
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”€ has-unicode@1.0.1
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”¬ lodash.pad@3.1.1
β”‚   β”‚ β”‚   β”‚   β”‚ β”œβ”€β”€ lodash._basetostring@3.0.1
β”‚   β”‚ β”‚   β”‚   β”‚ └─┬ lodash._createpadding@3.6.1
β”‚   β”‚ β”‚   β”‚   β”‚   └── lodash.repeat@3.0.1
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”€ lodash.padleft@3.1.1
β”‚   β”‚ β”‚   β”‚   └── lodash.padright@3.1.1
β”‚   β”‚ β”‚   β”œβ”€β”¬ rc@1.1.5
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ ini@1.3.4
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ minimist@1.2.0
β”‚   β”‚ β”‚   β”‚ └── strip-json-comments@1.0.4
β”‚   β”‚ β”‚   β”œβ”€β”¬ request@2.67.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ aws-sign2@0.6.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ bl@1.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ └─┬ readable-stream@2.0.4
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ core-util-is@1.0.2
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ inherits@2.0.1
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ isarray@0.0.1
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ string_decoder@0.10.31
β”‚   β”‚ β”‚   β”‚ β”‚   └── util-deprecate@1.0.2
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ caseless@0.11.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ combined-stream@1.0.5
β”‚   β”‚ β”‚   β”‚ β”‚ └── delayed-stream@1.0.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ extend@3.0.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ forever-agent@0.6.1
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ form-data@1.0.0-rc3
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ har-validator@2.0.3
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”¬ chalk@1.1.1
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ ansi-styles@2.1.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”¬ has-ansi@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”‚ └── ansi-regex@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ strip-ansi@3.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ └── supports-color@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”¬ commander@2.9.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ └── graceful-readlink@1.0.1
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”¬ is-my-json-valid@2.12.3
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ generate-function@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”¬ generate-object-property@1.2.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”‚ └── is-property@1.0.2
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ jsonpointer@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ └── xtend@4.0.1
β”‚   β”‚ β”‚   β”‚ β”‚ └─┬ pinkie-promise@2.0.0
β”‚   β”‚ β”‚   β”‚ β”‚   └── pinkie@2.0.1
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ hawk@3.1.2
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ boom@2.10.1
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ cryptiles@2.0.5
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ hoek@2.16.3
β”‚   β”‚ β”‚   β”‚ β”‚ └── sntp@1.0.9
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ http-signature@1.1.0
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ assert-plus@0.1.5
β”‚   β”‚ β”‚   β”‚ β”‚ β”œβ”€β”¬ jsprim@1.2.2
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ extsprintf@1.0.2
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ β”œβ”€β”€ json-schema@0.2.2
β”‚   β”‚ β”‚   β”‚ β”‚ β”‚ └── verror@1.3.6
β”‚   β”‚ β”‚   β”‚ β”‚ └─┬ sshpk@1.7.0
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ asn1@0.2.3
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ assert-plus@0.2.0
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ ecc-jsbn@0.1.1
β”‚   β”‚ β”‚   β”‚ β”‚   β”œβ”€β”€ jodid25519@1.0.2
β”‚   β”‚ β”‚   β”‚ β”‚   └── jsbn@0.1.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ is-typedarray@1.0.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ isstream@0.1.2
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ json-stringify-safe@5.0.1
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ node-uuid@1.4.7
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ oauth-sign@0.8.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ qs@5.2.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ stringstream@0.0.5
β”‚   β”‚ β”‚   β”‚ └── tough-cookie@2.2.1
β”‚   β”‚ β”‚   β”œβ”€β”¬ rimraf@2.4.4
β”‚   β”‚ β”‚   β”‚ └─┬ glob@5.0.15
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”¬ inflight@1.0.4
β”‚   β”‚ β”‚   β”‚   β”‚ └── wrappy@1.0.1
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”€ inherits@2.0.1
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”¬ minimatch@3.0.0
β”‚   β”‚ β”‚   β”‚   β”‚ └─┬ brace-expansion@1.1.1
β”‚   β”‚ β”‚   β”‚   β”‚   └── concat-map@0.0.1
β”‚   β”‚ β”‚   β”‚   β”œβ”€β”¬ once@1.3.3
β”‚   β”‚ β”‚   β”‚   β”‚ └── wrappy@1.0.1
β”‚   β”‚ β”‚   β”‚   └── path-is-absolute@1.0.0
β”‚   β”‚ β”‚   β”œβ”€β”€ semver@5.1.0
β”‚   β”‚ β”‚   β”œβ”€β”¬ tar@2.2.1
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ block-stream@0.0.8
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ fstream@1.0.8
β”‚   β”‚ β”‚   β”‚ └── inherits@2.0.1
β”‚   β”‚ β”‚   └─┬ tar-pack@3.1.0
β”‚   β”‚ β”‚     β”œβ”€β”€ debug@0.7.4
β”‚   β”‚ β”‚     β”œβ”€β”¬ fstream-ignore@1.0.3
β”‚   β”‚ β”‚     β”‚ └─┬ minimatch@3.0.0
β”‚   β”‚ β”‚     β”‚   └─┬ brace-expansion@1.1.1
β”‚   β”‚ β”‚     β”‚     └── concat-map@0.0.1
β”‚   β”‚ β”‚     β”œβ”€β”€ graceful-fs@4.1.2
β”‚   β”‚ β”‚     β”œβ”€β”¬ readable-stream@1.0.33
β”‚   β”‚ β”‚     β”‚ β”œβ”€β”€ core-util-is@1.0.2
β”‚   β”‚ β”‚     β”‚ β”œβ”€β”€ inherits@2.0.1
β”‚   β”‚ β”‚     β”‚ β”œβ”€β”€ isarray@0.0.1
β”‚   β”‚ β”‚     β”‚ └── string_decoder@0.10.31
β”‚   β”‚ β”‚     └── rimraf@2.2.8
β”‚   β”‚ β”œβ”€β”€ glob-parent@2.0.0
β”‚   β”‚ β”œβ”€β”¬ is-binary-path@1.0.1
β”‚   β”‚ β”‚ └── binary-extensions@1.4.0
β”‚   β”‚ β”œβ”€β”€ is-glob@2.0.1
β”‚   β”‚ └─┬ readdirp@2.0.0
β”‚   β”‚   β”œβ”€β”€ graceful-fs@4.1.2
β”‚   β”‚   └── minimatch@2.0.10
β”‚   β”œβ”€β”¬ outpipe@1.1.1
β”‚   β”‚ └─┬ shell-quote@1.4.3
β”‚   β”‚   β”œβ”€β”€ array-filter@0.0.1
β”‚   β”‚   β”œβ”€β”€ array-map@0.0.0
β”‚   β”‚   └── array-reduce@0.0.0
β”‚   └── through2@2.0.0
β”œβ”€β”€ grunt-contrib-clean@0.6.0
β”œβ”€β”¬ grunt-contrib-compress@0.14.0
β”‚ β”œβ”€β”¬ archiver@0.16.0
β”‚ β”‚ β”œβ”€β”€ async@1.4.2
β”‚ β”‚ β”œβ”€β”€ buffer-crc32@0.2.5
β”‚ β”‚ β”œβ”€β”¬ glob@5.0.15
β”‚ β”‚ β”‚ └── minimatch@3.0.0
β”‚ β”‚ β”œβ”€β”¬ lazystream@0.1.0
β”‚ β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚ β”œβ”€β”€ lodash@3.10.1
β”‚ β”‚ β”œβ”€β”€ readable-stream@1.0.33
β”‚ β”‚ β”œβ”€β”¬ tar-stream@1.2.2
β”‚ β”‚ β”‚ β”œβ”€β”€ bl@1.0.0
β”‚ β”‚ β”‚ └── end-of-stream@1.1.0
β”‚ β”‚ └─┬ zip-stream@0.6.0
β”‚ β”‚   β”œβ”€β”¬ compress-commons@0.3.0
β”‚ β”‚   β”‚ β”œβ”€β”¬ crc32-stream@0.3.4
β”‚ β”‚   β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚   β”‚ β”œβ”€β”€ node-int64@0.4.0
β”‚ β”‚   β”‚ └── readable-stream@1.0.33
β”‚ β”‚   β”œβ”€β”€ lodash@3.10.1
β”‚ β”‚   └── readable-stream@1.0.33
β”‚ β”œβ”€β”¬ chalk@1.1.1
β”‚ β”‚ β”œβ”€β”€ ansi-styles@2.1.0
β”‚ β”‚ β”œβ”€β”€ escape-string-regexp@1.0.4
β”‚ β”‚ β”œβ”€β”¬ has-ansi@2.0.0
β”‚ β”‚ β”‚ └── ansi-regex@2.0.0
β”‚ β”‚ β”œβ”€β”€ strip-ansi@3.0.0
β”‚ β”‚ └── supports-color@2.0.0
β”‚ └─┬ pretty-bytes@2.0.1
β”‚   β”œβ”€β”€ get-stdin@4.0.1
β”‚   β”œβ”€β”¬ meow@3.7.0
β”‚   β”‚ β”œβ”€β”¬ camelcase-keys@2.0.0
β”‚   β”‚ β”‚ └── camelcase@2.0.1
β”‚   β”‚ β”œβ”€β”€ decamelize@1.1.2
β”‚   β”‚ β”œβ”€β”¬ loud-rejection@1.2.0
β”‚   β”‚ β”‚ └── signal-exit@2.1.2
β”‚   β”‚ β”œβ”€β”€ map-obj@1.0.1
β”‚   β”‚ β”œβ”€β”¬ normalize-package-data@2.3.5
β”‚   β”‚ β”‚ β”œβ”€β”€ hosted-git-info@2.1.4
β”‚   β”‚ β”‚ β”œβ”€β”¬ is-builtin-module@1.0.0
β”‚   β”‚ β”‚ β”‚ └── builtin-modules@1.1.1
β”‚   β”‚ β”‚ └─┬ validate-npm-package-license@3.0.1
β”‚   β”‚ β”‚   β”œβ”€β”¬ spdx-correct@1.0.2
β”‚   β”‚ β”‚   β”‚ └── spdx-license-ids@1.1.0
β”‚   β”‚ β”‚   └─┬ spdx-expression-parse@1.0.2
β”‚   β”‚ β”‚     └── spdx-exceptions@1.0.4
β”‚   β”‚ β”œβ”€β”¬ read-pkg-up@1.0.1
β”‚   β”‚ β”‚ β”œβ”€β”¬ find-up@1.1.0
β”‚   β”‚ β”‚ β”‚ └── path-exists@2.1.0
β”‚   β”‚ β”‚ └─┬ read-pkg@1.1.0
β”‚   β”‚ β”‚   β”œβ”€β”¬ load-json-file@1.1.0
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”€ graceful-fs@4.1.2
β”‚   β”‚ β”‚   β”‚ β”œβ”€β”¬ parse-json@2.2.0
β”‚   β”‚ β”‚   β”‚ β”‚ └─┬ error-ex@1.3.0
β”‚   β”‚ β”‚   β”‚ β”‚   └── is-arrayish@0.2.1
β”‚   β”‚ β”‚   β”‚ └── pify@2.3.0
β”‚   β”‚ β”‚   └─┬ path-type@1.1.0
β”‚   β”‚ β”‚     └── graceful-fs@4.1.2
β”‚   β”‚ β”œβ”€β”¬ redent@1.0.0
β”‚   β”‚ β”‚ β”œβ”€β”¬ indent-string@2.1.0
β”‚   β”‚ β”‚ β”‚ └─┬ repeating@2.0.0
β”‚   β”‚ β”‚ β”‚   └── is-finite@1.0.1
β”‚   β”‚ β”‚ └── strip-indent@1.0.1
β”‚   β”‚ └── trim-newlines@1.0.0
β”‚   └── number-is-nan@1.0.0
β”œβ”€β”¬ grunt-contrib-concat@0.5.1
β”‚ β”œβ”€β”¬ chalk@0.5.1
β”‚ β”‚ β”œβ”€β”€ ansi-styles@1.1.0
β”‚ β”‚ β”œβ”€β”¬ has-ansi@0.1.0
β”‚ β”‚ β”‚ └── ansi-regex@0.2.1
β”‚ β”‚ β”œβ”€β”€ strip-ansi@0.3.0
β”‚ β”‚ └── supports-color@0.2.0
β”‚ └─┬ source-map@0.3.0
β”‚   └── amdefine@1.0.0
β”œβ”€β”¬ grunt-contrib-copy@0.8.2
β”‚ └── file-sync-cmp@0.1.1
β”œβ”€β”¬ grunt-contrib-cssmin@0.14.0
β”‚ β”œβ”€β”¬ clean-css@3.4.9
β”‚ β”‚ β”œβ”€β”¬ commander@2.8.1
β”‚ β”‚ β”‚ └── graceful-readlink@1.0.1
β”‚ β”‚ └── source-map@0.4.4
β”‚ └─┬ maxmin@1.1.0
β”‚   β”œβ”€β”€ figures@1.4.0
β”‚   β”œβ”€β”€ gzip-size@1.0.0
β”‚   └── pretty-bytes@1.0.4
β”œβ”€β”¬ grunt-contrib-imagemin@1.0.0
β”‚ β”œβ”€β”€ async@0.9.2
β”‚ β”œβ”€β”€ gulp-rename@1.2.2
β”‚ β”œβ”€β”¬ imagemin@4.0.0
β”‚ β”‚ β”œβ”€β”¬ buffer-to-vinyl@1.1.0
β”‚ β”‚ β”‚ β”œβ”€β”€ file-type@3.4.0
β”‚ β”‚ β”‚ β”œβ”€β”€ uuid@2.0.1
β”‚ β”‚ β”‚ └─┬ vinyl@1.1.0
β”‚ β”‚ β”‚   β”œβ”€β”€ clone@1.0.2
β”‚ β”‚ β”‚   β”œβ”€β”€ clone-stats@0.0.1
β”‚ β”‚ β”‚   └── replace-ext@0.0.1
β”‚ β”‚ β”œβ”€β”¬ imagemin-gifsicle@4.2.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ gifsicle@3.0.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ bin-build@2.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ archive-type@3.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ decompress@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ decompress-tar@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-tar@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ object-assign@2.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ strip-dirs@1.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-natural-number@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── sum-up@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ through2@0.6.5
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ vinyl@0.4.6
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── clone@0.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ decompress-tarbz2@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-bzip2@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ object-assign@2.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ seek-bzip@1.0.5
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ through2@0.6.5
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ vinyl@0.4.6
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── clone@0.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ decompress-targz@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-gzip@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ object-assign@2.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ through2@0.6.5
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ vinyl@0.4.6
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── clone@0.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ decompress-unzip@3.4.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-zip@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ stat-mode@0.2.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ through2@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ yauzl@2.4.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └─┬ fd-slicer@1.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚     └── pend@1.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ stream-combiner2@1.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── duplexer2@0.1.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── vinyl-assign@1.2.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ download@4.4.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ caw@1.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ get-proxy@1.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ rc@0.5.5
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ deep-extend@0.2.11
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ minimist@0.0.10
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── strip-json-comments@0.1.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-obj@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── object-assign@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ filenamify@1.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ filename-reserved-regex@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ strip-outer@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── trim-repeated@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ got@5.3.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ create-error-class@2.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── capture-stack-trace@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-plain-obj@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-redirect@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ lowercase-keys@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ node-status-codes@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ timed-out@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ unzip-response@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ url-parse-lax@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── prepend-http@1.0.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ gulp-decompress@1.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ gulp-util@3.0.7
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ array-differ@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ array-uniq@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ beeper@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ dateformat@1.0.12
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”¬ fancy-log@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ └── dateformat@1.0.12
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”¬ gulplog@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ └── glogg@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”¬ has-gulplog@0.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ └── sparkles@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ lodash._reescape@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ lodash._reevaluate@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ lodash._reinterpolate@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”¬ lodash.template@3.6.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash._basecopy@3.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash._basevalues@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash._isiterateecall@3.0.9
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash.escape@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”¬ lodash.keys@3.1.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ lodash._getnative@3.9.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”‚ β”œβ”€β”€ lodash.isarguments@3.0.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”‚ └── lodash.isarray@3.0.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash.restparam@3.6.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”‚ └── lodash.templatesettings@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ multipipe@0.1.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ object-assign@3.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ through2@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── vinyl@0.5.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ is-url@1.2.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ read-all-stream@3.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ pinkie-promise@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── pinkie@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ stream-combiner2@1.1.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── duplexer2@0.1.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ ware@1.3.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └─┬ wrap-fn@0.1.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚     └── co@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ exec-series@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── async-each-series@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ url-regex@3.1.0
β”‚ β”‚ β”‚ β”‚ β”‚   └── ip-regex@1.0.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ bin-wrapper@3.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ bin-check@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── executable@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ bin-version-check@2.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ bin-version@1.0.4
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └─┬ find-versions@1.2.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚   └── semver-regex@1.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ semver@4.3.6
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── semver-truncate@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ lazy-req@1.1.0
β”‚ β”‚ β”‚ β”‚ β”‚ └── os-filter-obj@1.0.3
β”‚ β”‚ β”‚ β”‚ └─┬ logalot@2.1.0
β”‚ β”‚ β”‚ β”‚   └─┬ squeak@1.3.0
β”‚ β”‚ β”‚ β”‚     β”œβ”€β”€ console-stream@0.1.1
β”‚ β”‚ β”‚ β”‚     └─┬ lpad-align@1.1.0
β”‚ β”‚ β”‚ β”‚       β”œβ”€β”€ longest@1.0.1
β”‚ β”‚ β”‚ β”‚       └── lpad@2.0.1
β”‚ β”‚ β”‚ β”œβ”€β”€ is-gif@1.0.0
β”‚ β”‚ β”‚ └─┬ through2@0.6.5
β”‚ β”‚ β”‚   └── readable-stream@1.0.33
β”‚ β”‚ β”œβ”€β”¬ imagemin-jpegtran@4.3.2
β”‚ β”‚ β”‚ β”œβ”€β”€ is-jpg@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ jpegtran-bin@3.0.6
β”‚ β”‚ β”‚ └── through2@2.0.0
β”‚ β”‚ β”œβ”€β”¬ imagemin-optipng@4.3.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ exec-buffer@2.0.1
β”‚ β”‚ β”‚ β”‚ └── tempfile@1.1.1
β”‚ β”‚ β”‚ β”œβ”€β”€ is-png@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ optipng-bin@3.0.4
β”‚ β”‚ β”‚ └─┬ through2@0.6.5
β”‚ β”‚ β”‚   └── readable-stream@1.0.33
β”‚ β”‚ β”œβ”€β”¬ imagemin-svgo@4.2.0
β”‚ β”‚ β”‚ β”œβ”€β”€ is-svg@1.1.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ svgo@0.6.1
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ coa@1.0.1
β”‚ β”‚ β”‚ β”‚ β”‚ └── q@1.4.1
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ colors@1.1.2
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ csso@1.4.4
β”‚ β”‚ β”‚ β”‚ β”‚ └── clap@1.0.10
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ js-yaml@3.4.6
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ argparse@1.0.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ lodash@3.10.1
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── sprintf-js@1.0.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ esprima@2.7.1
β”‚ β”‚ β”‚ β”‚ β”‚ └── inherit@2.2.2
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ sax@1.1.4
β”‚ β”‚ β”‚ β”‚ └── whet.extend@0.9.9
β”‚ β”‚ β”‚ └── through2@2.0.0
β”‚ β”‚ β”œβ”€β”€ optional@0.1.3
β”‚ β”‚ β”œβ”€β”¬ stream-combiner2@1.1.1
β”‚ β”‚ β”‚ └── duplexer2@0.1.4
β”‚ β”‚ └─┬ vinyl-fs@2.2.1
β”‚ β”‚   β”œβ”€β”¬ duplexify@3.4.2
β”‚ β”‚   β”‚ └── end-of-stream@1.0.0
β”‚ β”‚   β”œβ”€β”¬ glob-stream@5.3.1
β”‚ β”‚   β”‚ β”œβ”€β”¬ glob@5.0.15
β”‚ β”‚   β”‚ β”‚ └── minimatch@3.0.0
β”‚ β”‚   β”‚ β”œβ”€β”¬ ordered-read-streams@0.3.0
β”‚ β”‚   β”‚ β”‚ └── is-stream@1.0.1
β”‚ β”‚   β”‚ β”œβ”€β”¬ through2@0.6.5
β”‚ β”‚   β”‚ β”‚ └── readable-stream@1.0.33
β”‚ β”‚   β”‚ β”œβ”€β”¬ to-absolute-glob@0.1.1
β”‚ β”‚   β”‚ β”‚ └── extend-shallow@2.0.1
β”‚ β”‚   β”‚ └── unique-stream@2.2.0
β”‚ β”‚   β”œβ”€β”€ graceful-fs@4.1.2
β”‚ β”‚   β”œβ”€β”¬ gulp-sourcemaps@1.6.0
β”‚ β”‚   β”‚ β”œβ”€β”€ graceful-fs@4.1.2
β”‚ β”‚   β”‚ └── through2@2.0.0
β”‚ β”‚   β”œβ”€β”€ is-valid-glob@0.3.0
β”‚ β”‚   β”œβ”€β”€ merge-stream@1.0.0
β”‚ β”‚   β”œβ”€β”¬ strip-bom@2.0.0
β”‚ β”‚   β”‚ └── is-utf8@0.2.1
β”‚ β”‚   β”œβ”€β”¬ strip-bom-stream@1.0.0
β”‚ β”‚   β”‚ └── first-chunk-stream@1.0.0
β”‚ β”‚   β”œβ”€β”€ through2@2.0.0
β”‚ β”‚   └─┬ through2-filter@2.0.0
β”‚ β”‚     └── through2@2.0.0
β”‚ └── pretty-bytes@1.0.4
β”œβ”€β”¬ grunt-contrib-jshint@0.11.3
β”‚ └─┬ jshint@2.8.0
β”‚   β”œβ”€β”¬ cli@0.6.6
β”‚   β”‚ └─┬ glob@3.2.11
β”‚   β”‚   └── minimatch@0.3.0
β”‚   β”œβ”€β”¬ htmlparser2@3.8.3
β”‚   β”‚ β”œβ”€β”€ domelementtype@1.3.0
β”‚   β”‚ β”œβ”€β”€ domhandler@2.3.0
β”‚   β”‚ β”œβ”€β”¬ domutils@1.5.1
β”‚   β”‚ β”‚ └─┬ dom-serializer@0.1.0
β”‚   β”‚ β”‚   β”œβ”€β”€ domelementtype@1.1.3
β”‚   β”‚ β”‚   └── entities@1.1.1
β”‚   β”‚ β”œβ”€β”€ entities@1.0.0
β”‚   β”‚ └── readable-stream@1.1.13
β”‚   β”œβ”€β”€ lodash@3.7.0
β”‚   β”œβ”€β”€ minimatch@2.0.10
β”‚   β”œβ”€β”€ shelljs@0.3.0
β”‚   └── strip-json-comments@1.0.4
β”œβ”€β”¬ grunt-contrib-qunit@0.7.0
β”‚ └─┬ grunt-lib-phantomjs@0.6.0
β”‚   β”œβ”€β”¬ phantomjs@1.9.19
β”‚   β”‚ β”œβ”€β”€ adm-zip@0.4.4
β”‚   β”‚ β”œβ”€β”¬ fs-extra@0.23.1
β”‚   β”‚ β”‚ β”œβ”€β”€ graceful-fs@4.1.2
β”‚   β”‚ β”‚ └── jsonfile@2.2.3
β”‚   β”‚ β”œβ”€β”€ kew@0.4.0
β”‚   β”‚ β”œβ”€β”¬ md5@2.0.0
β”‚   β”‚ β”‚ β”œβ”€β”€ charenc@0.0.1
β”‚   β”‚ β”‚ β”œβ”€β”€ crypt@0.0.1
β”‚   β”‚ β”‚ └── is-buffer@1.0.2
β”‚   β”‚ β”œβ”€β”¬ npmconf@2.1.1
β”‚   β”‚ β”‚ β”œβ”€β”€ nopt@3.0.6
β”‚   β”‚ β”‚ └── semver@4.3.6
β”‚   β”‚ β”œβ”€β”€ progress@1.1.8
β”‚   β”‚ β”œβ”€β”¬ request@2.42.0
β”‚   β”‚ β”‚ β”œβ”€β”€ aws-sign2@0.5.0
β”‚   β”‚ β”‚ β”œβ”€β”¬ bl@0.9.4
β”‚   β”‚ β”‚ β”‚ └── readable-stream@1.0.33
β”‚   β”‚ β”‚ β”œβ”€β”€ caseless@0.6.0
β”‚   β”‚ β”‚ β”œβ”€β”€ hawk@1.1.1
β”‚   β”‚ β”‚ β”œβ”€β”€ mime-types@1.0.2
β”‚   β”‚ β”‚ β”œβ”€β”€ oauth-sign@0.4.0
β”‚   β”‚ β”‚ └── qs@1.2.2
β”‚   β”‚ └─┬ request-progress@0.3.1
β”‚   β”‚   └── throttleit@0.0.2
β”‚   β”œβ”€β”€ semver@1.0.14
β”‚   └─┬ temporary@0.0.8
β”‚     └── package@1.0.1
β”œβ”€β”¬ grunt-contrib-uglify@0.10.1
β”‚ β”œβ”€β”¬ chalk@1.0.0
β”‚ β”‚ β”œβ”€β”¬ has-ansi@1.0.3
β”‚ β”‚ β”‚ └── ansi-regex@1.1.1
β”‚ β”‚ β”œβ”€β”€ strip-ansi@2.0.1
β”‚ β”‚ └── supports-color@1.3.1
β”‚ β”œβ”€β”€ lodash@3.2.0
β”‚ β”œβ”€β”¬ maxmin@1.0.1
β”‚ β”‚ └── pretty-bytes@1.0.4
β”‚ β”œβ”€β”¬ uglify-js@2.5.0
β”‚ β”‚ β”œβ”€β”€ async@0.2.10
β”‚ β”‚ β”œβ”€β”€ uglify-to-browserify@1.0.2
β”‚ β”‚ └─┬ yargs@3.5.4
β”‚ β”‚   β”œβ”€β”€ camelcase@1.2.1
β”‚ β”‚   β”œβ”€β”€ window-size@0.1.0
β”‚ β”‚   └── wordwrap@0.0.2
β”‚ └── uri-path@1.0.0
β”œβ”€β”¬ grunt-contrib-watch@0.6.1
β”‚ β”œβ”€β”€ async@0.2.10
β”‚ β”œβ”€β”¬ gaze@0.5.2
β”‚ β”‚ └─┬ globule@0.1.0
β”‚ β”‚   └── lodash@1.0.2
β”‚ β”œβ”€β”€ lodash@2.4.2
β”‚ └─┬ tiny-lr-fork@0.0.5
β”‚   β”œβ”€β”€ debug@0.7.4
β”‚   β”œβ”€β”€ faye-websocket@0.4.4
β”‚   β”œβ”€β”¬ noptify@0.0.3
β”‚   β”‚ └── nopt@2.0.0
β”‚   └── qs@0.5.6
β”œβ”€β”€ grunt-includes@0.5.2
β”œβ”€β”¬ grunt-jsvalidate@0.2.2
β”‚ └── esprima@1.0.4
β”œβ”€β”€ grunt-legacy-util@0.2.0
β”œβ”€β”¬ grunt-patch-wordpress@0.3.0
β”‚ β”œβ”€β”¬ inquirer@0.2.5
β”‚ β”‚ β”œβ”€β”€ async@0.2.10
β”‚ β”‚ β”œβ”€β”¬ cli-color@0.2.3
β”‚ β”‚ β”‚ β”œβ”€β”€ es5-ext@0.9.2
β”‚ β”‚ β”‚ └─┬ memoizee@0.2.6
β”‚ β”‚ β”‚   β”œβ”€β”€ event-emitter@0.2.2
β”‚ β”‚ β”‚   └── next-tick@0.1.0
β”‚ β”‚ β”œβ”€β”€ lodash@1.2.1
β”‚ β”‚ └── mute-stream@0.0.3
β”‚ β”œβ”€β”¬ request@2.27.0
β”‚ β”‚ β”œβ”€β”€ aws-sign@0.3.0
β”‚ β”‚ β”œβ”€β”€ cookie-jar@0.3.0
β”‚ β”‚ β”œβ”€β”€ forever-agent@0.5.2
β”‚ β”‚ β”œβ”€β”¬ form-data@0.1.4
β”‚ β”‚ β”‚ β”œβ”€β”€ async@0.9.2
β”‚ β”‚ β”‚ └─┬ combined-stream@0.0.7
β”‚ β”‚ β”‚   └── delayed-stream@0.0.5
β”‚ β”‚ β”œβ”€β”¬ hawk@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ boom@0.4.2
β”‚ β”‚ β”‚ β”œβ”€β”€ cryptiles@0.2.2
β”‚ β”‚ β”‚ β”œβ”€β”€ hoek@0.9.1
β”‚ β”‚ β”‚ └── sntp@0.2.4
β”‚ β”‚ β”œβ”€β”¬ http-signature@0.10.1
β”‚ β”‚ β”‚ β”œβ”€β”€ asn1@0.1.11
β”‚ β”‚ β”‚ β”œβ”€β”€ assert-plus@0.1.5
β”‚ β”‚ β”‚ └── ctype@0.5.3
β”‚ β”‚ β”œβ”€β”€ json-stringify-safe@5.0.1
β”‚ β”‚ β”œβ”€β”€ mime@1.2.11
β”‚ β”‚ β”œβ”€β”€ node-uuid@1.4.7
β”‚ β”‚ β”œβ”€β”€ oauth-sign@0.3.0
β”‚ β”‚ β”œβ”€β”€ qs@0.6.6
β”‚ β”‚ └── tunnel-agent@0.3.0
β”‚ β”œβ”€β”€ underscore@1.5.2
β”‚ └── underscore.string@2.3.3
β”œβ”€β”¬ grunt-postcss@0.7.1
β”‚ β”œβ”€β”€ diff@2.2.1
β”‚ └── es6-promise@3.0.2
β”œβ”€β”¬ grunt-rtlcss@1.6.0
β”‚ └─┬ rtlcss@1.7.2
β”‚   β”œβ”€β”¬ findup@0.1.5
β”‚   β”‚ └── commander@2.1.0
β”‚   β”œβ”€β”¬ mkdirp@0.5.0
β”‚   β”‚ └── minimist@0.0.8
β”‚   └── strip-json-comments@1.0.4
β”œβ”€β”¬ grunt-sass@1.1.0
β”‚ β”œβ”€β”¬ each-async@1.1.1
β”‚ β”‚ β”œβ”€β”€ onetime@1.1.0
β”‚ β”‚ └── set-immediate-shim@1.0.1
β”‚ β”œβ”€β”¬ node-sass@3.4.2
β”‚ β”‚ β”œβ”€β”€ async-foreach@0.1.3
β”‚ β”‚ β”œβ”€β”¬ cross-spawn@2.1.4
β”‚ β”‚ β”‚ β”œβ”€β”¬ cross-spawn-async@2.1.6
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ lru-cache@4.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ pseudomap@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ └── yallist@2.0.0
β”‚ β”‚ β”‚ β”‚ └─┬ which@1.2.1
β”‚ β”‚ β”‚ β”‚   └─┬ is-absolute@0.1.7
β”‚ β”‚ β”‚ β”‚     └── is-relative@0.1.3
β”‚ β”‚ β”‚ └─┬ spawn-sync@1.0.15
β”‚ β”‚ β”‚   └── os-shim@0.1.3
β”‚ β”‚ β”œβ”€β”¬ glob@5.0.15
β”‚ β”‚ β”‚ └── minimatch@3.0.0
β”‚ β”‚ β”œβ”€β”¬ mkdirp@0.5.1
β”‚ β”‚ β”‚ └── minimist@0.0.8
β”‚ β”‚ β”œβ”€β”€ nan@2.1.0
β”‚ β”‚ β”œβ”€β”¬ node-gyp@3.2.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ fstream@1.0.8
β”‚ β”‚ β”‚ β”‚ └── graceful-fs@4.1.2
β”‚ β”‚ β”‚ β”œβ”€β”€ graceful-fs@4.1.2
β”‚ β”‚ β”‚ β”œβ”€β”€ minimatch@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ nopt@3.0.6
β”‚ β”‚ β”‚ β”œβ”€β”¬ npmlog@1.2.1
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ ansi@0.3.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ are-we-there-yet@1.0.5
β”‚ β”‚ β”‚ β”‚ β”‚ └── delegates@0.1.0
β”‚ β”‚ β”‚ β”‚ └─┬ gauge@1.2.2
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ has-unicode@1.0.1
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”¬ lodash.pad@3.1.1
β”‚ β”‚ β”‚ β”‚   β”‚ β”œβ”€β”€ lodash._basetostring@3.0.1
β”‚ β”‚ β”‚ β”‚   β”‚ └─┬ lodash._createpadding@3.6.1
β”‚ β”‚ β”‚ β”‚   β”‚   └── lodash.repeat@3.0.1
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ lodash.padleft@3.1.1
β”‚ β”‚ β”‚ β”‚   └── lodash.padright@3.1.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ osenv@0.1.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ os-homedir@1.0.1
β”‚ β”‚ β”‚ β”‚ └── os-tmpdir@1.0.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ path-array@1.0.0
β”‚ β”‚ β”‚ β”‚ └── array-index@0.1.1
β”‚ β”‚ β”‚ β”œβ”€β”€ semver@5.1.0
β”‚ β”‚ β”‚ └─┬ tar@2.2.1
β”‚ β”‚ β”‚   └── block-stream@0.0.8
β”‚ β”‚ β”œβ”€β”¬ npmconf@2.1.2
β”‚ β”‚ β”‚ β”œβ”€β”¬ config-chain@1.1.9
β”‚ β”‚ β”‚ β”‚ └── proto-list@1.2.4
β”‚ β”‚ β”‚ β”œβ”€β”€ ini@1.3.4
β”‚ β”‚ β”‚ β”œβ”€β”€ nopt@3.0.6
β”‚ β”‚ β”‚ β”œβ”€β”€ semver@4.3.6
β”‚ β”‚ β”‚ └── uid-number@0.0.5
β”‚ β”‚ β”œβ”€β”¬ request@2.67.0
β”‚ β”‚ β”‚ β”œβ”€β”€ aws-sign2@0.6.0
β”‚ β”‚ β”‚ β”œβ”€β”€ caseless@0.11.0
β”‚ β”‚ β”‚ β”œβ”€β”¬ combined-stream@1.0.5
β”‚ β”‚ β”‚ β”‚ └── delayed-stream@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ extend@3.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ forever-agent@0.6.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ form-data@1.0.0-rc3
β”‚ β”‚ β”‚ β”‚ └── async@1.5.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ har-validator@2.0.3
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ commander@2.9.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ is-my-json-valid@2.12.3
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ generate-function@2.0.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ generate-object-property@1.2.0
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ └── is-property@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ └── jsonpointer@2.0.0
β”‚ β”‚ β”‚ β”‚ └─┬ pinkie-promise@2.0.0
β”‚ β”‚ β”‚ β”‚   └── pinkie@2.0.1
β”‚ β”‚ β”‚ β”œβ”€β”¬ hawk@3.1.2
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ boom@2.10.1
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ cryptiles@2.0.5
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ hoek@2.16.3
β”‚ β”‚ β”‚ β”‚ └── sntp@1.0.9
β”‚ β”‚ β”‚ β”œβ”€β”¬ http-signature@1.1.0
β”‚ β”‚ β”‚ β”‚ β”œβ”€β”¬ jsprim@1.2.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ extsprintf@1.0.2
β”‚ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ json-schema@0.2.2
β”‚ β”‚ β”‚ β”‚ β”‚ └── verror@1.3.6
β”‚ β”‚ β”‚ β”‚ └─┬ sshpk@1.7.2
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ asn1@0.2.3
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ assert-plus@0.2.0
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ dashdash@1.11.0
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ ecc-jsbn@0.1.1
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ jodid25519@1.0.2
β”‚ β”‚ β”‚ β”‚   β”œβ”€β”€ jsbn@0.1.0
β”‚ β”‚ β”‚ β”‚   └── tweetnacl@0.13.3
β”‚ β”‚ β”‚ β”œβ”€β”€ is-typedarray@1.0.0
β”‚ β”‚ β”‚ β”œβ”€β”€ isstream@0.1.2
β”‚ β”‚ β”‚ β”œβ”€β”¬ mime-types@2.1.9
β”‚ β”‚ β”‚ β”‚ └── mime-db@1.21.0
β”‚ β”‚ β”‚ β”œβ”€β”€ oauth-sign@0.8.0
β”‚ β”‚ β”‚ β”œβ”€β”€ qs@5.2.0
β”‚ β”‚ β”‚ β”œβ”€β”€ stringstream@0.0.5
β”‚ β”‚ β”‚ β”œβ”€β”€ tough-cookie@2.2.1
β”‚ β”‚ β”‚ └── tunnel-agent@0.4.2
β”‚ β”‚ └─┬ sass-graph@2.0.1
β”‚ β”‚   β”œβ”€β”¬ glob@5.0.15
β”‚ β”‚   β”‚ └── minimatch@3.0.0
β”‚ β”‚   β”œβ”€β”€ lodash@3.10.1
β”‚ β”‚   └─┬ yargs@3.31.0
β”‚ β”‚     β”œβ”€β”¬ cliui@3.1.0
β”‚ β”‚     β”‚ └── wrap-ansi@1.0.0
β”‚ β”‚     β”œβ”€β”¬ os-locale@1.4.0
β”‚ β”‚     β”‚ └─┬ lcid@1.0.0
β”‚ β”‚     β”‚   └── invert-kv@1.0.0
β”‚ β”‚     β”œβ”€β”¬ string-width@1.0.1
β”‚ β”‚     β”‚ β”œβ”€β”€ code-point-at@1.0.0
β”‚ β”‚     β”‚ └── is-fullwidth-code-point@1.0.0
β”‚ β”‚     β”œβ”€β”€ window-size@0.1.4
β”‚ β”‚     └── y18n@3.2.0
β”‚ └── object-assign@4.0.1
└─┬ matchdep@1.0.0
  β”œβ”€β”¬ findup-sync@0.3.0
  β”‚ └─┬ glob@5.0.15
  β”‚   └── minimatch@3.0.0
  β”œβ”€β”¬ globule@0.2.0
  β”‚ β”œβ”€β”¬ glob@3.2.11
  β”‚ β”‚ └── minimatch@0.3.0
  β”‚ β”œβ”€β”€ lodash@2.4.2
  β”‚ └── minimatch@0.2.14
  └── stack-trace@0.0.9

And this is just for WordPress core; it doesn’t include the tools we use for BuddyPress or bbPress.

I don’t like this. I don’t like not knowing what these tools do or why they’re necessary. It feels like having one-thousand hammers instead of drill-bits and screwdrivers and power-tools. It’s not immediately obvious what the return on learning each or any of these unique tools is.

And when a tool becomes obsolete or out-of-date, the rabbit hole is full of eels:

npm WARN deprecated lodash@0.9.2: lodash@<2.0.0 is no longer maintained. Upgrade to lodash@^3.0.0
npm WARN deprecated npmconf@2.1.1: this package has been reintegrated into npm and is now out of date with respect to npm
npm WARN deprecated lodash@1.0.2: lodash@<2.0.0 is no longer maintained. Upgrade to lodash@^3.0.0
npm WARN deprecated lodash@1.2.1: lodash@<2.0.0 is no longer maintained. Upgrade to lodash@^3.0.0
npm WARN deprecated npmconf@2.1.2: this package has been reintegrated into npm and is now out of date with respect to npm
npm WARN deprecated lodash@2.4.2: lodash@<3.0.0 is no longer maintained. Upgrade to lodash@^3.0.0.
n

These relatively helpful messages may be outside of your control. They might be directly your fault. They might be globally installed modules or locally installed ones. Upgrading might be good for WordPress but break everything else you work on without warning.

Here’s usually what happens:

  • Something in the mystery toolbox breaks and complains about it
  • Try to upgrade the broken tool according to the feedback message(s)
  • The tool is still broken
  • Delete the entire `node_modules` directory and `npm install` again
  • Fixed!

Now, I understand what’s going on here is a miracle of modern software engineering. An enormous amount of automation is going on here, and the fact it actually works most of the time I’ll consider another closely coupled miracle. It still feels like there must be a better way, even though I can’t claim the fame of knowing right now what that might actually be.

I get that this is all awesome. I get that this process, and having & using these tools, is better than smashing things with rocks and hoping for the best. I get that a ton of work has gone into making this as seamless and wrinkle-free as possible.

I accept it, and work with it, and try not to think about it, but the trend of installing and trusting hundreds of tiny unknown libraries feels a little too organic and alive for a man-made computing machine. Like millions of nerve-endings and neurons and vessels and muscles working in unison to blink your eyes and sip on some coffee, the line between being a software developer or a software doctor is an increasingly jagged one.

If we aren’t careful, we’ll end up as lost amongst our own creations as we are inside of mother nature’s.