JJJ's Blog

  • WordPress
  • GitHub
  • Twitter/X
  • Facebook Remembers

    Social networks and social media are weird. I'm deleting my Facebook account, but I'm not just deactivating it – I'm going post by post, comment by comment, through my entire 10 year history and deleting each agonizing thing one at a time.

    It's insane. I'm insane. And Facebook knew I was insane way before I did.

    Something weird happens on modern day social networking applications and websites that I never experienced on previous generation forum type software. I'm sure this phenomenon has a name; I'm sure folks smarter than me knew about what I'm about to describe years and years ago; now that I've recognized it, I'm going to try to outline it here so that I never repeat myself.

    I bet older generations had a version of this, too, but I bet it happened in person instead.


    So, because applications like Facebook and Twitter are all about me seeing you, and because we've cemented our friendship with a formal request and acknowledgment, and because I choose to follow you, I think I have a relationship with you that I never really had. I see your posts, photos, and updates, and I think "this person wants me to engage with them" when, frankly, that's unlikely to ever be the case.

    The reason I know this, is because I can look through every single comment and post on 10 years worth of Facebook content, see that there are people who I frequently respond to, who do not respond back. Ever.

    I'm not mad that you don't like or comment. It doesn't bother me. The problem is that algorithmic platforms like Facebook and Twitter DO, and they use the patterns of our relationships (or the anti-patterns of our non-relationships) against us, without telling us exactly how.


    For example: I've basically forgotten about 99% of the things I've ever said online, usually instantly after hitting publish, but Facebook will never forget. And they're able to calculate the intersection of times we've had interactions back and forth, over all of our online years, to identify that I like you more than you like me. I literally like your posts and comments more than you like mine, and Facebook has always known this.

    It's fine that they know this, I guess. What's not fine is that they don't say that they know this, and that they use that knowledge to manipulate our entire interaction with their platform, by: weighting posts and comments higher or lower so that we are more or less likely to read or engage with them; by showing us ads that might make us feel better or worse based on things our friends bought or sold; by tricking us into thinking that by me saying "congratulations" to you that you'll remember that I'm still back here working towards accomplishing something that maybe you'll congratulate me back for later too. Jesus.

    None of this is about privacy settings, or who stole my information, or who gave my information to what advertisers, because I gave it away for free first. The risk was mine to take, and I took it; I have no one to blame but myself, so just like I'm responsible for whatever the online version is of me that Facebook and Twitter and everyone else think you should see, I need to be responsible for taking that power away from them.


    Platforms like Facebook and Twitter are our worst friends. They know us at an intimate level, at our best and at our worst, and they use everything we say and do against us…

    I want to see what exactly they're using against me, and what they gain from it. Pennies? Dollars? What does it cost them to host my 600 images, and what do they gain from me allowing their advertisers to scan through those images to identify that I own several LEGO sets, an XBOX, have 2 dogs, and so on.

    I want control over their narrative. I want to be able to tell them "I don't actually like my XBOX; I only play 1 game, and it's buggy as shit, so it sucks and all that mining that you did was worthless and you're wrong."

    I want to be able to say "I'm only friends with this person here because I think declining their request feels unkind, so even though I'd prefer they not have access to everything, and even though I'd prefer to not have to go through the work of blocking them but still somehow being friends, they aren't actually anyone I am friends with."


    Obviously you and I are friends; besties, even. I mean, you've made it this far, right? But a lot of other people read something I post, don't get what they expected from me, think that I'm crazy or whatever, and don't engage. Maybe you unfollowed me. Maybe they mute me. I'll never know.

    Platforms like Facebook and Twitter are too much like real life, in all the bad ways that make us insecure, neurotic, and just a bit foolish because it's not even real life or whatever.

    Lots of folks online are not my friends, but current generation social platforms are built to show us the best of what we asked to see. I actually do think it feels pretty natural to engage in conversations you find interesting from people you care about, regardless of how much they care about you back.

    This is basically how folks like my mother like and repost everything that they see. Yes, it's process addiction. But it's also the best way they have available to them to use the platform everyone they care about is on in a way that enables them to "prove how much they care" a million times a day.

    It's super weird, and really unhealthy, but kinda cute, I guess?


    So, that shit stops now for me. I'm done commenting on stuff. I'm done liking stuff. I mean… I'll like it, but I'm just going to assume that you know I like it because you know I like you, and support you, and want to see you succeed. And if you need validation from me, or miss hanging out, I expect you'll reach out and say so.

    I want to double down on work, on real life stuff, and solving bigger harder problems. No more likes or comments. Just work, results, and healthy positive reciprocating caring relationships. Hopefully, that's with you. 💜

    In a way, this all feels wrong, which I think is why it's probably right. If less is more, than nothing is most, and silence is golden. Peace, and humptiness forever. 😶

    JJJ

    April 11, 2018
    Rants, Uncategorized
    Twitter, Facebook
  • Computers are the worst

    JJJ

    August 25, 2017
    Rants
  • The thing about snow…

    It just snowed here in southeastern Wisconsin; like there’s a winter storm warning and there’s probably 13 inches of the stuff everywhere.

    I haven’t put the winter tires on the BRZ yet, because there hasn’t been any indication or need until there is now, an immediate need – and it’s too late to do it because the car is undrivable in the snow without them.

    That’s the thing about snow, and stuff… by the time you can get something, it’s usually already too late and you don’t need it anymore.

    JJJ

    December 17, 2016
    Rants
  • Afraid to Click

    Users of the Internet in the United States are starting to experience what millions of others in many other nations have dealt with since the widespread deployment of the world-wide web:

    Fear.

    As the web evolves, an increasing amount of control is being exercised, or at least recognized as an opportunity that maybe wasn’t really achievable until more modern generations of client & server technologies emerged.

    Even a simple Tweet becomes a questionable, yet enticing, click…

    Excellent plan. If you want to talk and it's risky, go to a public computer, far from home & work, and start here: https://t.co/IvVdo4gUOV. https://t.co/ozKjnBOed2

    — Barton Gellman (@bartongellman) December 12, 2016

    This is an experience I haven’t really felt – at least not since being a teenager galavanting around AOL chat rooms where literally everything was a risky click – but it is a relatively common way of life for so many already. When there’s so much unchecked information about us out amongst the world, it becomes really easy for someone to create their own narratives based on your search history, browsing history, bookmarks, online chat histories, et al.

    I think all most of us can do is continue doing whatever we can to keep the web a free & openly accessible place, and try our best to create safe places to congregate with one-another.

    JJJ

    December 13, 2016
    Rants
  • Apple Trackpad Issues, Explained

    I’ve experienced (and deeply investigated) the same exact trackpad issues on my 2012 retina MacBook Pro that people are now reporting in 2016, and Im going to share my experience with y’all.

    Here’s how you replicate this issue on ANY retina Mac since 2012:

    • Put the cursor on any side of the screen
    • Remember where the cursor is on the screen
    • Don’t touch your Mac for at least 5 seconds
    • With any number of fingers, and from any side of the trackpad, try to move the cursor to the opposite side of the screen
    • You will notice a split-second where the cursor jumps
    • The trackpad is listening because the cursor does quickly catch-up

    TL;DR – it’s working as it’s designed to work. Some Apple employees will go to great lengths to listen and help; others will say they do not see what you’re seeing & get annoyed with you quickly.


    I had these same /exact/ trackpad issues the day I unboxed my maxed out 15″ retina MacBook Pro. Before that, I had a 13″ Air and a Mac Mini which did not exhibit any trackpad delay. I even paired the Magic Trackpad from my Mini to my Pro to rule-out the onboard hardware, and the trackpad issue was persistent across both.

    That rMBP had a bevy of other issues. Aside from trackpad delay from day 0, a stick of RAM died, the display was the LG that had severe image retention, the hard drive failed, and eventually a GPU, all of which led to me paying $350 for Apple depot in 2015, and Apple eventually swapping out the top half (screen) and bottom half (main board, internals, including glass trackpad & keyboard.)

    I had made so many repair trips, I started fiddling with demo units, and was able to narrow down which exact PCs had this issue. I also travel frequently for work, so I started going into every Apple Store in every city I was in, to check their machines for this problem, and all retina laptops have it – not the Air, Mini, or Pro (even when connected to 4K displays.) Maybe not the iMac, but I don’t remember because I was never interested in purchasing one.

    I ended up buying an 11″ Air as my daily machine to replace my lemon of a 15″ rMBP, and it was a flawless workhorse. [I now use a 12″ MacBook, and it had a rough start to life, but is now also very great (even with the cursor delay.)]

    Anyways, after back-to-back trips to Apple depot for top & bottom replacements, my old laptop was now comprised of only new-to-me hardware & still exhibited the exact same trackpad delay even on the El Capitan installation screen (I checked before I left the store.)

    I chucked at the (very nice) Apple employee, and told him they could keep the stupid thing – I didn’t want it anymore & I already had an Air to use. He gave me the number to Apple corporate, and I gave up – I never called, because I was the only person annoyed by this, and it  issue was much bigger than me.

    So… rather than fix the issue, Apple introduces a mouse-jiggle animation to find a lost cursor instead.


    The problem is palm rejection. It was originally an option in System Preferences, but Apple decided you’d never want this off, so they force-activited it & removed it for us. Here’s how it works:

    • You move the cursor to do something, and stop for a few seconds
    • Apple averages the time between input transitions to be about 5 seconds (if you haven’t moved the mouse again, it’s unlikely you’re going to soon.)
    • In software, macOS feathers the edges of the trackpad that are listening for input, to cancel out the tiny palm nudges you are bound to make on a laptop
    • If you start from the center and move outwards, the trackpad works perfectly
    • If you start from the edge and move inwards, the trackpad appears broken and glitchy
      Bigger trackpads and external displays exacerbate the was a User perceives this glitchiness

    My conclusions:

    • There is no cure for everyone for this problem, because everyone uses the trackpad differently, and everyone perceives the delay differently
    • All modern retina Mac devices have this issue, but many people never notice it. Even when you show it to them, they are able to tolerate it & work around it.
    • It’s plausible there’s an old bug in the accidental palm rejection software, since this is retina only. Maybe the calculation between trackpad-size to display DPI is off, causing the larger 15″ tbMBP to make this more obvious?
    • If there’s a terminal command to turn off palm rejection entirely (or to tune its sensitivity) I never bothered with it. Maybe the old setting is still in there somewhere and users can disable it.
    • Why it isn’t disabled when using a Bluetooth Magic Trackpad seems like a bug to me, but I never filed a report to Apple aside from the numerous in-store visits and what-not.

     


    Hopefully Apple is able to debug this further for an improved UX. As display technology improves and more people move towards externals for production, the delay becomes more noticeable to more professionals with high expectations on expensive hardware.

    If anyone has questions, I’ll try to reply when I see them. If anyone from Apple wants to chime in, that’d be pretty neat too. ❤️

    JJJ

    November 21, 2016
    Rants, Opinion, Hardware
    Apple, Trackpad
  • Berenstein/stain Bears

    Do you remember The Berenstain Bears?

    Do you, like millions of others, misremember them as the Berenstein Bears? I remember reading about this years ago, and now the web has caught up – people are freaking out about glitches in the Matrix, alternate realities, and other malarkey.

    Brace for impact…

    It’s always been “Berenstain”.

    I very vividly remember my 2nd grade teacher “correcting” my saying “stain” in front of the entire class. I used to read books to the class, repeatedly, every week. The Pokey Little Puppy, The Monster at the End of This Book, and a bunch of other favorites that my mom used to read to me.

    The Berenstain Bears was one of them.

    This phenomena was created by adults without appreciation for detail, who propagated one mispronunciation to impressionable young minds. It’s the same as everyone playing Monopoly incorrectly for decades.

    Human minds naturally trust ubiquity & do not reprocess solved problems.

    The lesson? People all around you accidentally influence your perceptions, in ways that have seemingly invisible yet long-lasting effects.

    Concepts like discrimination, racism, classism, ageism, and so on, are ideas handed down to us by the people that came before us.

    You can continue believing what your memories have convinced you over-time as real, or you can accept reality as it presents itself today, tomorrow, and everyday thereafter.

    There are no super heroes or villains. No aliens. No ghosts. No time travel. And definitely, without question, no Berenstein Bears. 🐻

    JJJ

    September 9, 2016
    Rants
  • Tone

    Tone is more important than the words you use, until all you have is words. On the web, we’ve skirted tone for a long while with emoticons. :) Thankfully, the wide adoption of Emoji is rescuing us from writing obscure combinations of syntactically invalid punctuation, and I think that’s a good thing.

    If you read as much as I do, then you already know words like “just” & “that” unintentionally discredit your ideas and pitches; you know body language & confidence will win people over more than a lexicon of jargon; you know how hard it is to put biases aside and trust the data.

    The data about written communication, is that we all suck at it.

    Everyone, across the board, at both reading & writing, sucks at it, including me. I spend a lot of time, most of my professional career, not just thinking about social software, but how to improve both the value and the return-on-investment of the ways people socialize online. I think the answer, for me, is etiquette.

    Different groups of people, teams, factions, etc… have an established rapport. They found communication styles & mechanisms that work well enough for them to have considered that problem solved-enough, so they can move onto solving bigger problems. When these patterns deviate outside of traditional or societal norms, is when it becomes increasingly difficult to break into those groups.

    On a large scale, I can’t break into the Japanese WordPress User Group because I don’t speak a lick of Japanese. On a smaller scale, I can’t help my village planning commission make decisions because I don’t know any of the ordinances. At home, I can’t tell what Paul the dog is really thinking because he only understands a few dozen words and I don’t speak dog very well.

    For teams of humans, working together to address intersecting needs, we’ve worked for thousands of years to lower the barrier of entry into these groups. Grunts turned into syllables, words, phrases, and sentences. We introduced syntactical structure to convey pauses, stops, and rests. But when the web exploded, we froze almost all written language because it’s now the web’s biggest dependency. We can’t delete “Q” from the English language entirely because wp_enqueue_script wouldn’t work anymore.

    All of this is to say, that we need to learn how to do better with what we have today, because there won’t be much new for the rest of our lives when it comes to written communication. To do that, means a few different things…

    • Lurk. We all need to read, listen, & absorb. This includes understanding the general vibe of who is all involved, and deciding if it’s compatible with you.
    • Respect. Groups of people have established processes. No one can change these easily, especially someone new & full of enthusiasm to rock everyone’s worlds.
    • Decide. You need to choose where you think you fall in the pecking order, and make no mistake, there is a pecking order. Even flat organizations have a hidden social hierarchy. Understanding Social Dominance Theory will help you, here.
    • Introduce. Once you have enough data from lurking, you can slowly start to apply what you’ve learned. Sometimes this means humor, sometimes strictly business, or other times it means only lurking and not getting involved at all.
    • Pace. Now that you understand the social dynamic, and have decided where you think you belong in the group, it’s time to try to keep the pace. Traditionally, this is called “fitting in” but it’s important to earning the trust of your new acquaintances.
    • Pass/fail. You’ll know pretty quickly whether any of your above efforts have resonated positively or negatively, and each interaction will echo through-out the group. Someone will mention you, one way or the other.
    • Stay/bail. The level of joy you receive from any group of people should be the underlying motivator for driving your decision to stay or leave. If it’s rewarding, healthy, and fun, then stay. If it’s causing harm to yourself or others, my advice would be to consider anything else.

    “Us vs. Them” is a real feeling, because we are – all of us – are constantly at odds with each other. In our base programming, we are animals, sizing each other up, and fighting for scraps. Sure; we are mostly domesticated animals, but during times of distress or high-anxiety, you can watch people become animals & treat other people that way too, and triggers could literally be anything from allergies to relationship issues to PTSD and on…

    When it comes to WordPress’s leadership, or BuddyPress/bbPress, or really anything else, these same rules apply, but increasingly so because almost all of our communication is non-verbal. This means a million people may read your words and hear kindness in your written voice, but the one person you want to hear kindness may only hear rage, for reasons that may or may not have anything to do with anything you did or did not do. Phew!

    My proposed solution, is etiquette. More pleases, more thank-you’s, more awareness of who is involved in what, who is in charge of what, who has earned what, and who the who’s are and what they want to be when they grow up. This means a base-level respect for everyone, regardless of your history or lack-there-of. It means reading your words back to yourself and trying to convey a smile without using :) or 😀.

    Ultimately, it means being patient, and taking the time to craft your words so they will sound like a well-intentioned contribution to your audience.

    For slowing down, I’ll recommend you try switching your keyboard layout. In 2010, I switched to Dvorak – when my 100wpm plummeted to 20, those 20 words needed to matter most. Twitter’s 140 character limit maybe helps with being succinct, but I don’t know that length is as important as word-choice and knowing your audience.

    Lastly, it helps to know yourself, and have a relatively clear idea of who the people around you think that you are, and how similar that is to who you think you are. If people think you’re always goofy, and you think you have something serious to offer, changing that perception is not going to be easy, and it may take a number of years to swing people around to accepting your style & approach for what it is.

    I think if everyone has a bit more patience with each other, and we all take the time to consider the ripples we leave in people’s lives, we can communicate with written words in ways that don’t sink ships or hurt feelings. <3

    JJJ

    August 23, 2016
    Rants, Opinion, Software
  • Today's Software is Terrible

    Are you a software developer? I am, and everyday I’m embarrassed by my profession.

    Every single day, I run across some website, app, video-game, program or plugin that is egregiously broken; embarrassingly broken; 5000-developers-with-six-figure-salaries-and-free-catered-lunches-and-still-can’t-get-it-right, broken.

    Apps on my phone, tablet, computer, tv, and car, crash constantly, sometimes resulting in actual data loss. We shoved television behind a pay-wall in a cube that buffers and loads more than it presents anything. We broke copy & paste, because who would ever want to paste a password anywhere? Form fields do this shit where they want to autocomplete and autocorrect and autofill 3 different suggestions at once. We connected wrist-watches to the internet to draw doodles back and forth that don’t even send half the time. We hid mechanical engines behind electronics so complex there is noticeable lag driving performance cars. We connected entertainment systems to airplane diagnostic systems, so passengers can see how high up they are. We connect doors to the web to unlock them remotely, but firmware updates brick them and now you’re locked out of your house. We connect smoke detectors to the web and now the entire house & every connected device in it is beeping because you grilled a burger-patty, and the app on your phone to stop them isn’t responding.

    Today’s software is a perpetual nightmare machine of non-stop frustrations.

    Writing software is hard, mostly for reasons that don’t actually involve the software itself. I could go on about stakeholders, or how project managers are whatever. I could say that developers should be left alone to concentrate. I could say it’s nobody’s fault because it’s everybody’s fault. I could say all kinds of trite crap to poorly defend the people that populate the position I hold most dear, and currently the most fun job I think anyone could ever hope to perform.

    I could say lots of things, but they’d all be lies.

    The harsh truth is that many of you shouldn’t be writing software for production use, because you’re just not that good at it yet. You’re not experienced. You haven’t shipped anything. You don’t know how to recover from the damage you will inevitably cause.

    You break people’s shit – constantly, anonymously, and without repercussion. You aren’t meticulous in your life, you don’t care about etiquette, so you won’t do your employer any better, and you certainly won’t care if any of your users complain on Twitter.

    Sure; mistakes happen. We all overlook stuff. That’s how you learn, right? By repeating and improving and discovering what you missed the previous times. And there is more to discover everyday, because there are more & more design patterns and philosophies and dependencies and processes and teams and stakeholders and deadlines and Carl called in sick and no one understands what he even does here anymore but it’s suddenly critical to today’s problems and why is this line of code 500 characters long and who messed up all this whitespace and why can’t we all agree not to use ternaries and why does this class inherit from 5 other classes and on and on and on.

    Software is eating the world, but… garbage in, garbage out. So, what can we do?

    1. Be meticulous. Someone will undoubtedly refer to you as OCD, or apply some other insulting derogatory bullshit label. Screw them; they suck at their job anyway.
    2. Pay attention, to everything. You are the Axel Foley of software development. Writing code and fixing bugs is target practice for your soul. Do it constantly, rearrange the pieces in your mind while you shower, and take everything in. This means watching, listening, learning, while writing less and solving more.
    3. Be vigilant. Everything around you is intricately balanced and ready to come crashing down at a misplaced semi-colon’s notice. I’m not joking. You can very easily cause millions of dollars in revenue losses by breaking just 1 dependency in a complex chain. Code is poetry, but it’s also contagious.
    4. Be respectful. Push your chair in. Hold the door for everyone. Smile at people, even when you’re grumpy. Someone has to maintain the terrible decisions you’ve made once you level-up & move-on, and that’s easier to do when you like the person who’s shadow you’re in.
    5. Contribute to open-source. This is where you earn your lumps; not behind closed doors, not in a sweet corporate environment, and not sitting at a desk sipping a mocha-latté. You need to jump up on stage, give your best performance, and embrace the tomatoes and boos, because you’re probably going to be terrible for your first few rounds.
    6. If it ain’t fun, it ain’t right. Once you stop feeling joy from the software you’re writing, it’s time to move onto something else. Sitting still and being complacent isn’t healthy, even if it feels pretty natural not to burn all those calories moving on to newer and more exciting endeavors.
    7. Make friends. Like, real ones. Ones that will come to your wedding from across the country. These are the people that will remind you how good you are when you need them to, and they’ll have your back when you’re not having fun anymore.
    8. Learn how to make soup. Not even kidding. Understanding how to make the best of what few ingredients you have is essential to writing good software. Embrace your constraints, and don’t be afraid of butter or salt because they’re universally delicious.
    9. Challenge authority constantly. Most people have no idea what they’re doing. They were asked or tasked with a problem, and either they follow the above methods or they pass the problem on to someone else. They’re in a holding pattern, until the next big thing happens to them, instead of making big things happen around them.
    10. Find mentors everywhere. Follow a person around that you want to be like, take bits of pieces of what works for them, and apply them to your life. Steal, plagiarize, and sample small enough traits until you’re an amalgamation of the hippest, funniest, most awesome people you’ve ever come across.

    Then, after all of that, sit down and write the best ‘effing software anyone has ever used. ❤️

    JJJ

    August 4, 2016
    Rants, Software
  • Good and Evil

    This past Friday, my car got hit by a motorcycle. There’s a story there, but this post isn’t about that. Rather, it’s about people’s perception of the rider.

    He must have been speeding.

    He must not have been paying attention.

    He must not know how to ride.

    None of this is actually true, though. He wasn’t speeding, he was paying attention (mostly) and is a veteran rider with about 25 years experience.

    Generally, I think for “most people”, it’s maximally convenient and efficient to categorize things (and people, and ideas) in the most extremely polarizing way, and then work inwards towards an understanding or acceptance of that thing.

    I also think this is why I have hard time navigating the world; I think of everything as inside-out vs. outside-in. My starting line is in the middle, and my Good-o-meter(TM) swings based on whether I found joy or pain in that thing.

    There are currently a few members of our local village government that have reputations for not being very friendly, for having ideas & beliefs that go against the grain, and for being a bit confrontational. And that reputation has glorified them into villains, which is pretty silly if you stop and think about the individuals.

    There is no Good and there is no Evil. There is no right and there is no wrong. There is only circumstance and action, or a lack of either or both.

    Everyone chooses how to act or feel based on their awareness of what’s appropriate, what’s possible, and what their level of maturity is in dealing with those situations. The circumstances for this motorcyclist are different than mine with my car are different than the eyewitnesses.

    It’s easy to feel like someone closing your issue on Github makes them a terribly stupid person who does not understand the importance of the issue you’ve raised. It’s easy to think your WordPress core ticket sitting around for 5 years means no one cares. It’s easy to say someone sucks because of something they’ve said or done you don’t agree with.

    It’s easy to assume that mass shooters are crazy, that they’ve snapped, or any other extreme set of rules that polarize the perpetrator. Who knows, and the why almost doesn’t even matter, because it doesn’t change the outcome, and not much will be done to prevent similar outcomes in the future. What if someone broke his heart, and he couldn’t cope? Do we suddenly try to prevent all future heartbreak?

    There will always be unpredictable terrible circumstances created by human-kind, and it requires collective bravery and awareness to reduce the consequences of those harmful decisions. (And full disclosure, it’s my experience in my own life that “most people” are neither aware nor brave, meaning my outlook on the pool of resources available to make positive change is, honestly, bleak.)

    It’s equally easy to say homosexuality is evil. Or being pro-life is evil. Or white-dudes are evil rapists. These are all obviously incorrect assessments; and… think of all the times you’ve identified something as bad (or felt wrongly profiled by someone) and imagine that there are millions of people that find genuine joy in that thing without you.

    Instead of starting with good or evil, please train yourself to start from the middle and let the circumstances steer your assessment about the variable value of a thing in your life. Actively avoid extremes, and politely remind others that people are people, and heroes & villains are figments of their imaginations.

    Be objective. Be sincere. Be better.

    JJJ

    June 15, 2016
    Rants, Life
  • 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.

    JJJ

    January 7, 2016
    Rants, Opinion, Software, WordPress
1 2
Next Page

Proudly Powered by WordPress