outsourcing your webapp maintenance to debian
DESCRIPTION
Today's web applications often have a lot of external dependencies. Start off with a basic framework, sprinkle a couple of handy modules and finish with a generous serving of JavaScript front-end libraries. What you end up is a gigantic mess of code from different sources which follow very different release schedules and policies. Language-specific package managers can automate much of the dependency resolution and package installation, but you're on your own in terms of integration and quality assurance. Also, the minute you start distributing someone else's code with your project, you become responsible for the security of that third-party code. We moved away from statically-linked C/C++ programs a long time ago and now (mostly) live in a nicely-packaged shared library world. Can we leverage the power of Debian (i.e. the great work of the package maintainers and security team) to similarly reduce the burden of those who end up having to maintain our webapps? This talk will examine the decision that the Libravatar project made to outsource much of its maintenance burden to Debian by using system packages for almost everything. https://summit.debconf.org/debconf14/meeting/16/outsourcing-your-webapp-maintenance-to-debian/TRANSCRIPT
#!/bin/sh###### by Francois Marier <[email protected]>#
apt-get updateapt-get -y upgrade
Outsourcing your webappmaintenance to Debian
dependenciesin webapps
dependenciesin webapps
case study
dependenciesin webapps
case study
approach
dependenciesin webapps
case study
approach results
dependenciesin webapps
case studydiscussion
approach results
external depencies inweb applications
$ ls vendor/packages/
amqplibanyjsonBeautifulSoupbeautifulsoup4bleachcelerydecoratordistributeDjangodjango-assetsdjango-authopeniddjango-celerydjango-debug-toolbardjango-extensionsdjango-inplaceeditdjango-invitationdjango-kombudjango-model-utilsdjango-picklefielddjango-registrationdjango-reversiondjango-tastypiedjango-votingdjango-webtestdj-database-urldocutilsfeedparsergdataghettoqhtml2text
html5libimportlibJinja2jsminkombumarkupsafemechanizemimeparsemockodictordereddictpygeoipPygmentspython-dateutilpython-memcachedpython-mimeparsepython-openidpython-otppython-patchpytzPyYamlrequestsscrapysessionprofilesixsouthsphinxsqlparsestaticgeneratortwilltwistedtypecheck
unicodecsvunittest-xml-reportingwebobwebtestwhooshzope.interface
[email protected] ├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── shelljs @0.1.4
├─┬ [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected]
│ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] └─┬ [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected] │ ├── [email protected]
│ └── [email protected] ├─┬ [email protected]
│ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected]
[email protected] ├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── shelljs @0.1.4
├─┬ [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected]
│ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] └─┬ [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected] │ ├── [email protected]
│ └── [email protected] ├─┬ [email protected]
│ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected]
[email protected] ├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── shelljs @0.1.4
├─┬ [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected]
│ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] └─┬ [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected] │ ├── [email protected]
│ └── [email protected] ├─┬ [email protected]
│ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected]
1.4.4
1.2.4
1.1.7 1.5.2
not a new problem
c/c++ dynamic linking
shared libraryinstead of bundling
fix libbroken once
fix libbroken once
maintaineruploads the newupstream version
fix libbroken once
maintaineruploads the newupstream version
security teampatches the
stable package
How to leverage thiswork in our webapps?
libravatar.org
libravatar.org
delivering (federated) avatarsto third-party websites
www
www
cdn2cdn1 cdn4 cdn5
www
cdn2cdn1 cdn4 cdn5
www
cdn2cdn1 cdn4 cdn5
www
cdn2cdn1 cdn4 cdn5
www
cdn2cdn1 cdn4 cdn5
www
cdn2cdn1 cdn4 cdn5yours?
0110e86fdb31486c22dd381326d99de9
http://gravatar.com/avatar/0110e86...
$ dig SRV _avatars._tcp.fmarier.org
; <<>> DiG 9.9.5-4-Debian <<>> SRV _avatars._tcp.fmarier.org;; global options: +cmd;; Got answer:;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48289;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 4096;; QUESTION SECTION:;_avatars._tcp.fmarier.org. IN SRV
;; ANSWER SECTION:_avatars._tcp.fmarier.org. 3600 IN SRV 1 0 80 fmarier.org.
;; Query time: 137 msec;; SERVER: 192.168.1.1#53(192.168.1.1);; WHEN: Sat Aug 16 14:45:04 EDT 2014;; MSG SIZE rcvd: 85
http://fmarier.org/avatar/0110e86...
http://cdn.libravatar.org/avatar/
https://seccdn.libravatar.org/avatar/
a pretty simpleweb application
guidelines
only use Python libraries thatare packaged for Debian
guidelines
1.
only use Python libraries thatare packaged for Debian
only use the version fromthe latest Debian release
guidelines
1.
2.
libravatar*.deb
build:
“upstream” makefile
build: $(MINIFY) $(COMPRESS) mofiles
“upstream” makefile
build: $(MINIFY) $(COMPRESS) mofiles...
test:
“upstream” makefile
build: $(MINIFY) $(COMPRESS) mofiles...
test: pep8 pyflakes pylint unittests...
“upstream” makefile
libravatar.deblibravatar-www.deblibravatar-cdn.deblibravatar-seccdn.deblibravatar-cdn-common.deblibravatar-common.deb...
reprepro
fabric
keeping mirrors up to date
apt-get update
apt-get upgrade
How did it go?
limited choice of libraries
python-gearman.libgearman
python-gearman
$ apt-cache search ^python- | grep ^python | wc -l
2248
$ apt-cache search ^python3-| grep ^python | wc -l
656
cannot use the latest features
Libravatar is a verylow-maintainance service
Problems I ran into
optimizing for sysadminsinstead of developers
non-minified jQuery
cannot easily useunattended-upgrades
apticron report [Sat, 23 Aug 2014 10:11:08 +0000]=================================================
apticron has detected that some packages needupgrading on:
husavik [ 162.x.x.x 10.x.x.x 2001::37f0 ] [ 162.x.x.x 2001::37f0 ]
The following packages are currently pending anupgrade:
python-django 1.4.5-1+deb7u8
=================================================
security updates notalways timely in Debian
if you notice...
if you notice...
you can help out withbackporting or testing!
if you don't notice...
if you don't notice...
better late than never!
www
Is it realistic?
django
system libraries
deb packaging
What would be a good fit?
not your full-time job
not your full-time job
uses a mature framework
e.g. side project
e.g. consulting company
[email protected] ├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ └─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ ├── [email protected] │ │ │ │ └── [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ ├─┬ [email protected] │ │ │ │ └── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └── [email protected] │ │ └── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ ├── shelljs @0.1.4
├─┬ [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected]
│ │ │ └── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ ├── [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ └── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ ├── [email protected] │ └─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] └─┬ [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected] │ ├── [email protected]
│ └── [email protected] ├─┬ [email protected]
│ └─┬ [email protected] │ └── [email protected]
├─┬ [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ ├─┬ [email protected] │ │ └─┬ [email protected] │ │ └── [email protected] │ ├─┬ [email protected] │ │ ├── [email protected] │ │ ├── [email protected] │ │ └── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ └── [email protected]
├─┬ [email protected] │ ├─┬ [email protected] │ │ └── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├── [email protected] │ └── [email protected]
├── [email protected] ├── [email protected] ├── [email protected] ├─┬ [email protected]
│ ├── [email protected] │ ├─┬ [email protected] │ │ ├─┬ [email protected] │ │ │ ├── [email protected] │ │ │ └─┬ [email protected] │ │ │ └── [email protected]
© 2014 François Marier <[email protected]>This work is licensed under aCreative Commons Attribution-ShareAlike 4.0 License.
Questions?