[
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\n_site\ntest.js"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\ngem 'github-pages'"
  },
  {
    "path": "LICENSE.md",
    "content": "This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/deed.en_US."
  },
  {
    "path": "Makefile",
    "content": "build:\n\tstylus -o assets/css/ ./_stylus/main.styl\n\nserve:\n\tjekyll serve --watch --config _config-local.yml\n\nbooks:\n\tcat ./_includes/translation/rus/[0-9]*.md | sed 's/<!-- //g' | sed 's/-->//g' > ./epub/_source.md\n\tpandoc ./epub/_source.md -o ./epub/largescale-js.epub --toc-depth=2 --epub-cover-image=./epub/cover.jpg --epub-chapter-level=2\n\tpandoc ./epub/_source.md -o ./epub/largescale-js.fb2 --toc-depth=2 --epub-cover-image=./epub/cover.jpg --epub-chapter-level=2\n\tkindleGen -c1 -locale ru  ./epub/largescale-js.epub -o largescale-js.mobi\n\trm ./epub/_source.md\n\n.PHONY: build\n"
  },
  {
    "path": "README.md",
    "content": "# Паттерны для масштабируемых JavaScript-приложений\n\nПеревод на русский язык. Эдди Османи [в курсе][1].\n\n## Участники\n\n    project  : largescaleJS_ru\n    repo age : 3 months\n    active   : 57 days\n    commits  : 405\n    files    : 140\n    authors  : \n        295  Shuvalov Anton          72.8%\n         45  Vladimir Starkov        11.1%\n         22  Rakhim Davletkaliyev    5.4%\n         10  andreyr82               2.5%\n          7  FMRobot                 1.7%\n          7  Maxim Gladkih           1.7%\n          4  Nikita Bayev            1.0%\n          2  theghostbel             0.5%\n          2  Sergei Khaletskiy       0.5%\n          2  Vlad Tsepelev           0.5%\n          1  Mikhail Baranov         0.2%\n          1  Andrew                  0.2%\n          1  Vladimir                0.2%\n          1  Artem Sapegin           0.2%\n          1  Andrey Rachkov          0.2%\n          1  croupier                0.2%\n          1  finico                  0.2%\n          1  rakeev                  0.2%\n          1  Vadim Makeev            0.2%\n\n\n## Разработчикам\n\nГлавы на английском языке и на русском лежат в директории *[./_includes/translation/][2]*\n\nВ оформлении markdown мы стараемся придерживаться [правил][3] от Frontender Magazine.\n\nЛокально сайт можно запустить примерно так:\n\n    git clone https://github.com/shuvalov-anton/largescaleJS_ru.git largescalejs\n    cd $_\n    bundle install\n    stylus -w -o assets/css/ ./_stylus/main.styl\n    jekyll serve --watch\n\nВерсия для электронных книг, к сожалению, совершенно не зависит от других файлов.\nСобирать новые книги так:\n\n    cd ./epub\n    pandoc epub.md -o largescale-js.epub --toc-depth=2 --epub-cover-image=cover.jpg --epub-chapter-level=2\n    pandoc epub.md -o largescale-js.fb2 --toc-depth=2 --epub-cover-image=cover.jpg --epub-chapter-level=2\n    kindleGen -c1 -locale ru  largescale-js.epub -o largescale-js.mobi\n\n[1]: https://twitter.com/addyosmani/status/415195066895171584\n[2]: https://github.com/shuvalov-anton/Patterns-For-Large-Scale-JavaScript-Application-Architecture/tree/gh-pages/_includes/translation\n[3]: https://github.com/FMRobot/FM-guidelines\n"
  },
  {
    "path": "_config.yml",
    "content": "author: \"Эдди Османи\"\ntitle: \"Паттерны для масштабируемых JavaScript-приложений\"\n\nmarkdown: kramdown\nexclude: ['Gemfile', 'Gemfile.lock', 'makefile']\npygments: true\n\nproduction_url: http://largescalejs.ru\nbaseurl: /\npermalink: /:title\n"
  },
  {
    "path": "_includes/adsense.html",
    "content": "<script async src=\"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js\"></script>\n<!-- asd -->\n<ins class=\"adsbygoogle\"\n     style=\"display:inline-block;width:160px;height:600px\"\n     data-ad-client=\"ca-pub-6516049090709228\"\n     data-ad-slot=\"2241186794\"></ins>\n<script>\n(adsbygoogle = window.adsbygoogle || []).push({});\n</script>"
  },
  {
    "path": "_includes/analytics.html",
    "content": "<script>\n  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n\n  ga('create', 'UA-26825614-4', 'largescalejs.ru');\n  ga('send', 'pageview');\n\n</script>\n\n<script type=\"text/javascript\">\n  var _gauges = _gauges || [];\n  (function() {\n    var t   = document.createElement('script');\n    t.type  = 'text/javascript';\n    t.async = true;\n    t.id    = 'gauges-tracker';\n    t.setAttribute('data-site-id', '52d853db8bfdf733d0003b00');\n    t.src = '//secure.gaug.es/track.js';\n    var s = document.getElementsByTagName('script')[0];\n    s.parentNode.insertBefore(t, s);\n  })();\n</script>\n"
  },
  {
    "path": "_includes/disqus.html",
    "content": "<div id=\"disqus_thread\"></div>\n<script type=\"text/javascript\">\n    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */\n    var disqus_shortname = 'largescalejavascript'; // required: replace example with your forum shortname\n\n    /* * * DON'T EDIT BELOW THIS LINE * * */\n    (function() {\n        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;\n        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';\n        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);\n    })();\n</script>\n<noscript>Please enable JavaScript to view the <a href=\"http://disqus.com/?ref_noscript\">comments powered by Disqus.</a></noscript>\n<a href=\"http://disqus.com\" class=\"dsq-brlink\">comments powered by <span class=\"logo-disqus\">Disqus</span></a>\n"
  },
  {
    "path": "_includes/footer-adsense.html",
    "content": "<script async src=\"//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js\"></script>\n<!-- footer [largescalejs] -->\n<ins class=\"adsbygoogle\"\n     style=\"display:inline-block;width:728px;height:90px\"\n     data-ad-client=\"ca-pub-6516049090709228\"\n     data-ad-slot=\"1445451195\"></ins>\n<script>\n(adsbygoogle = window.adsbygoogle || []).push({});\n</script>\n"
  },
  {
    "path": "_includes/fork-me.html",
    "content": "<a style=\"position: absolute\" class=\"github__badge\" href=\"https://github.com/shuvalov-anton/Patterns-For-Large-Scale-JavaScript-Application-Architecture\"><img style=\"position: absolute; top: 0; left: 0; border: 0;\" src=\"https://s3.amazonaws.com/github/ribbons/forkme_left_red_aa0000.png\" alt=\"Fork me on GitHub\"></a>"
  },
  {
    "path": "_includes/lazada-banner.html",
    "content": "<a class=\"lazada-banner\" href=\"http://hh.ru/vacancy/13227361\">\n</a>\n"
  },
  {
    "path": "_includes/license.html",
    "content": "<p class='license'>\n  <a rel=\"license\" href=\"http://creativecommons.org/licenses/by/4.0/deed.en_US\">\n    <img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http://i.creativecommons.org/l/by/4.0/80x15.png\" />\n  </a>\n</p>\n"
  },
  {
    "path": "_includes/money.html",
    "content": "<div class=\"money\" id=\"donate\">\n  <iframe frameborder=\"0\" allowtransparency=\"true\" scrolling=\"no\" src=\"https://money.yandex.ru/embed/donate.xml?account=410011017781955&quickpay=donate&payment-type-choice=on&default-sum=100&targets=%D0%9C%D1%8B+%D0%B4%D0%B5%D0%BB%D0%B0%D0%BB%D0%B8+%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%BE%D0%B4+%D0%B2+%D1%81%D0%B2%D0%BE%D0%B5+%D1%81%D0%B2%D0%BE%D0%B1%D0%BE%D0%B4%D0%BD%D0%BE%D0%B5+%D0%B2%D1%80%D0%B5%D0%BC%D1%8F+%D0%B8+%D0%BD%D0%B0%D0%BC+%D0%B1%D1%83%D0%B4%D0%B5%D1%82+%D0%BE%D1%87%D0%B5%D0%BD%D1%8C+%D0%BF%D1%80%D0%B8%D1%8F%D1%82%D0%BD%D0%BE+%D0%B5%D1%81%D0%BB%D0%B8+%D0%B2%D1%8B+%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D1%82%D0%B5+%D0%BD%D0%B0%D1%81.&target-visibility=on&project-name=largescalejs.ru&project-site=http%3A%2F%2Flargescalejs.ru&button-text=05\" width=\"508\" height=\"147\"></iframe>\n</div>"
  },
  {
    "path": "_includes/page-header.html",
    "content": "<header class=\"page-header\">\n  <a class=\"page-header__rss-link\" href=\"/atom.xml\">r</a>\n  <a class=\"page-header__twitter-link\" href=\"https://twitter.com/largescaleJS_ru\"></a>\n  <h4>\n    {%if page.subtitle %}\n      <small>\n        {{ page.subtitle }}\n      </small>\n    {% else %}\n      <small>\n        <a href=\"/\" class=\"ignore-visited\">«{{ site.title }}»</a> от {{ site.author }}\n      </small>\n    {% endif %}</h4>\n  <h1 class=\"page-header__title\"><a class=\"page-header__title-link\" href=\"{{ page.url }}\">{{ page.title }}</a></h1>\n</header>\n"
  },
  {
    "path": "_includes/posts.html",
    "content": "<ul>\n  {% for post in site.posts reversed %}\n    {% if post.published %}\n      <li><a href=\"{{ post.url }}\">{{ post.title }}</a></li>\n    {% else %}\n      <li class='unpublished-post'>{{ post.title }}</li>\n    {% endif %}\n  {% endfor %}\n</ul>"
  },
  {
    "path": "_includes/prevnext.html",
    "content": "{% if page.previous or page.next %}\n  <div class=\"prevnext\">\n    {% if page.previous and page.previous.published %}\n      <div class=\"prevnext__previous\">\n        <small><span class=\"prevnext__previous-arrow\">&larr;</span><a rel=\"prev\" href=\"{{ page.previous.url }}\">{{ page.previous.title }}</a></small>\n      </div>\n    {% endif %}\n    {% if page.next and page.next.published %}\n      <div class=\"prevnext__next\">\n        <small><span class=\"prevnext__next-arrow\">&rarr;</span><a rel=\"next\" href=\"{{ page.next.url }}\">{{ page.next.title }}</a></small>\n      </div>\n    {% endif %}\n  </div>\n{% endif %}"
  },
  {
    "path": "_includes/prose.html",
    "content": "{% if page.index == true %}\n{% else %}\n<span>\n  Если вы заметили ошибку, вы всегда можете <a class=\"ignore-visited\" href=\"http://prose.io/#shuvalov-anton/largescaleJS_ru/edit/gh-pages/_includes/{{ page.path }}\">исправить ее</a> с помощью prose.io.\n</span>\n{% endif %}\n"
  },
  {
    "path": "_includes/social-likes.html",
    "content": "<ul class=\"social-likes\">\n  <li class=\"facebook\" title=\"Share link on Facebook\">Facebook</li>\n  <li class=\"vkontakte\" title=\"Share link on VK\">Вконтакте</li>\n  <li class=\"twitter\" title=\"Share link on Twitter\">Twitter</li>\n</ul>"
  },
  {
    "path": "_includes/translation/eng/00_intro.md",
    "content": "### Today we're going to discuss an effective set of patterns for large-scale\nJavaScript application architecture. The material is based on my talk of the \nsame name, last presented at LondonJS and inspired by[previous work][1] by\nNicholas Zakas.\n\n\n### Who am I and why am I writing about this topic?\n\nI'm currently a JavaScript and UI developer at AOL helping to plan and write\nthe front-end architecture to our next generation of client-facing applications.\nAs these applications are both complex and often require an architecture that is\nscalable and highly-reusable, it's one of my responsibilities to ensure the \npatterns used to implement such applications are as sustainable as possible.\n\nI also consider myself something of a design pattern enthusiast (although there\nare far more knowledgeable experts on this topic than I). I've previously \nwritten the creative-commons book\n'[Essential JavaScript Design Patterns][2]' and am in the middle of writing the\nmore detailed follow up to this book at the moment.\n\n\n### Can you summarize this article in 140 characters?\n\nIn the event of you being short for time, here's the tweet-sized summary of\nthis article:\n\nDecouple app. architecture w/module,facade & mediator patterns. Mods publish\nmsgs, mediator acts as pub/sub mgr & facade handles security\n\n\n[1]: http://yuilibrary.com/theater/nicholas-zakas/zakas-architecture/\n[2]: http://addyosmani.com/resources/essentialjsdesignpatterns/book/"
  },
  {
    "path": "_includes/translation/eng/01_what-exactly-is-a-large-javascript-application.md",
    "content": "### What exactly *is* a 'large' JavaScript application?\n\nBefore we begin, let us attempt to define what we mean when we refer to a\nJavaScript application as being significantly 'large'. This is a question I've \nfound still challenges developers with many years of experience in the field and\nthe answer to this can be quite subjective.\n\nAs an experiment, I asked a few intermediate developers to try providing their\ndefinition of it informally. One developer suggested 'a JavaScript application \nwith over 100,000 LOC' whilst another suggested 'apps with over 1MB of \nJavaScript code written in-house'. Whilst valiant (if not scary) suggestions, \nboth of these are**incorrect** as the size of a codebase does not always\ncorrelate to application complexity - those 100,000 LOC could easily represent \nquite trivial code.\n\nMy own definition may or may not be universally accepted, but I believe that it\n's closer to what a large application actually represents.\n\nIn my view, large-scale JavaScript apps are **non-trivial** applications\nrequiring**significant** developer effort to maintain, where most heavy lifting\nof data manipulation and display falls to the**browser**. \n\nThe last part of this definition is possibly the most significant."
  },
  {
    "path": "_includes/translation/eng/02_lets-review-your-current-architecture.md",
    "content": "### Let's review your current architecture.\n\nIf working on a significantly large JavaScript application, remember to\ndedicate**sufficient time** to planning the underlying architecture that makes\nthe most sense. It's often more complex than you may initially imagine.\n\nI can't stress the importance of this enough - some developers I've seen\napproach larger applications have stepped back and said 'Okay. Well, there are a\nset of ideas and patterns that worked well for me on my last medium-scale \nproject. Surely they should mostly apply to something a little larger, right?'. \nWhilst this may be true to an extent, please don't take it for granted\n- **larger apps generally have greater concerns that need to be factored in**.\nI'm going to discuss shortly why spending a little more time planning out the \nstructure to your application is worth it in the long run.\n\nMost JavaScript developers likely use a mixed combination of the following for\ntheir current architecture:\n\n*   custom widgets\n*   models\n*   views\n*   controllers\n*   templates\n*   libraries/toolkits\n*   an application core. \n\nYou probably also break down your application's functionality into blocks of\nmodules or apply other patterns for this. This is great, but there are a number \nof potential problems you can run into if this represents all of your \napplication's structure.\n\n\n##### 1. How much of this architecture is instantly re-usable? \n\nCan single modules exist on their own independently? Are they self-contained?\nRight now if I were to look at the codebase for a large application you or your \nteam were working on and selected a random module, would it be possible for me \nto easily just drop it into a new page and start using it on its own?. You may \nquestion the rationale behind wanting to do this, however I encourage you to \nthink about the future. What if your company were to begin building more and \nmore non-trivial applications which shared some cross-over in functionality?. If\nsomeone said, 'Our users love using the chat module in our mail client. Let's \ndrop that into our new collaborative editing suite', would this be possible \nwithout significantly altering the code?\n\n\n##### 2. How much do modules depend on other modules in the system? \n\nAre they tightly coupled? Before I dig into why this is a concern, I should\nnote that I understand it's not always possible to have modules with absolutely \nno other dependencies in a system. At a granular level you may well have modules\nthat extend the base functionality of others, but this question is more-so \nrelated to groups of modules with distinct functionality. It should be possible \nfor all of these distinct sets of modules to work in your application without \ndepending on too many other modules being present or loaded in order to function.\n\n\n##### 3. If specific parts of your application fail, can it still function? \n\nIf you're building a GMail-like application and your webmail module (or modules\n) fail, this shouldn't block the rest of the UI or prevent users from being able\nto use other parts of the page such as chat. At the same time, as per before, \nmodules should ideally be able to exist on their own outside of your current \napplication architecture. In my talks I mention dynamic dependency (or module) \nloading based on expressed user-intent as something related. For example, in \nGMail's case they might have the chat module collapsed by default without the \ncore module code loaded on page initialization. If a user expressed an intent to\nuse the chat feature, only then would it be dynamically loaded. Ideally, you \nwant this to be possible without it negatively affecting the rest of your \napplication.\n\n\n##### 4. How easily can you test individual modules?\n\nWhen working on systems of significant scale where there's a potential for\nmillions of users to use (or mis-use) the different parts it, it's essential \nthat modules which may end up being re-used across a number of different \napplications be sufficiently tested. Testing needs to be possible for when the \nmodule both inside and outside of the architecture for which it was initially \nbuilt. In my view, this provides the most assurance that it shouldn't break if \ndropped into another system."
  },
  {
    "path": "_includes/translation/eng/03_think-long-term.md",
    "content": "### Think Long Term\n\nWhen devising the architecture for your large application, it's important to\nthink ahead. Not just a month or a year from now, but beyond that. What might \nchange? It's of course impossible to guess exactly how your application may grow,\nbut there's certainly room to consider what is likely. Here, there is at least \none specific aspect of your application that comes to mind.\n\nDevelopers often couple their DOM manipulation code quite tightly with the rest\nof their application - even when they've gone to the trouble of separating their\ncore logic down into modules. Think about it..why is this not a good idea if we'\nre thinking long-term?\n\nOne member of my audience suggested that it was because a rigid architecture\ndefined in the present may not be suitable for the future. Whilst certainly true,\nthere's another concern that may cost even more if not factored in.\n\nYou may well decide to **switch** from using Dojo, jQuery, Zepto or YUI to\nsomething entirely different for reasons of performance, security or design in \nthe future. This can become a problem because libraries are not easily \ninterchangeable and have high switching costs if tightly coupled to your app.\n\nIf you're a Dojo developer (like some of the audience at my talk), you may not\nhave something better to switch to in the present, but who is to say that in 2-3\nyears something better doesn't come out that you'll want to switch to?\n.\n\nThis is a relatively trivial decision in smaller codebases but for larger\napplications, having an architecture which is flexible enough to support **not**\ncaring about the libraries being used in your modules can be of great benefit,\nboth financially and from a time-saving perspective.\n\nTo summarize, if you reviewed your architecture right now, could a decision to\nswitch libraries be made without rewriting your entire application?. If not, \nconsider reading on because I think the architecture being outlined today may be\nof interest.\n\nThere are a number of influential JavaScript developers who have previously\noutlined some of the concerns I've touched upon so far. Three key quotes I would\nlike to share from them are the following:\n\n\"The secret to building large apps is never build large apps. Break your\napplications into small pieces. Then, assemble those testable, bite-sized pieces\ninto your big application\n\" - **Justin Meyer, author JavaScriptMVC**\n\n\"The key is to acknowledge from the start that you have no idea how this will\ngrow. When you accept that you don't know everything, you begin to design the \nsystem defensively. You identify the key areas that may change, which often is \nvery easy when you put a little bit of time into it. For instance, you should \nexpect that any part of the app that communicates with another system will \nlikely change, so you need to abstract that away.\n\" - **Nicholas Zakas, author 'High-performance JavaScript websites'**\n\nand last but not least:\n\n\"The more tied components are to each other, the less reusable they will be,\nand the more difficult it becomes to make changes to one without accidentally \naffecting another\n\" - **Rebecca Murphey, author of jQuery Fundamentals.** These principles are\nessential to building an architecture that can stand the test of time and should\nalways be kept in mind.\n"
  },
  {
    "path": "_includes/translation/eng/04_brainstorming.md",
    "content": "### Brainstorming\n\nLet's think about what we're trying to achieve for a moment. \n\nWe want a loosely coupled architecture with functionality broken down into **\nindependent modules** with ideally no inter-module dependencies. Modules **\nspeak** to the rest of the application when something interesting happens and\nan**intermediate layer** interprets and reacts to these messages. \n\nFor example, if we had a JavaScript application responsible for an online\nbakery, one such 'interesting' message from a module might be 'batch 42 of bread\nrolls is ready for dispatch\n'. \n\nWe use a different layer to interpret messages from modules so that a) modules\ndon't directly access the core and b) modules don't need to directly call or \ninteract with other modules. This helps prevent applications from falling over \ndue to errors with specific modules and provides us a way to kick-start modules \nwhich have fallen over.\n\nAnother concern is security. The reality is that most of us don't consider\ninternal application security as that much of a concern. We tell ourselves that \nas we're structuring the application, we're intelligent enough to figure out \nwhat should be publicly or privately accessible.\n\nHowever, wouldn't it help if you had a way to determine what a module was\npermitted to do in the system? eg. if I know I've limited the permissions in my \nsystem to not allow a public chat widget to interface with an admin module or a \nmodule with DB-write permissions, I can limit the chances of someone exploiting \nvulnerabilities I have yet to find in the widget to pass some XSS in there. \nModules shouldn’t be able to access everything. They probably can in most \ncurrent architectures, but do they really need to be able to?\n\nHaving an intermediate layer handle permissions for which modules can access\nwhich parts of your framework gives you added security. This means a module is \nonly able to do at most what we’ve permitted it do.\n\n\n## The Proposed Architecture\n\nThe solution to the architecture we seek to define is a combination of three\nwell-known design patterns: the**module**, **facade** and **mediator**.\n\nRather than the traditional model of modules directly communicating with each\nother, in this decoupled architecture, they'll instead only publish events of \ninterest (ideally, without a knowledge of other modules in the system). The \nmediator pattern will be used to both subscribe to messages from these modules \nand handle what the appropriate response to notifications should be. The facade \npattern will be used to enforce module permissions.\n\nI will be going into more detail on each of these patterns below:"
  },
  {
    "path": "_includes/translation/eng/05_module-theory.md",
    "content": "### Module Theory \n\nYou probably already use some variation of modules in your existing\narchitecture. If however, you don't, this section will present a short primer on\nthem.\n\nModules are an **integral** piece of any robust application's architecture and\nare typically single-purpose parts of a larger system that are interchangeable.\n\nDepending on how you implement modules, it's possible to define dependencies\nfor them which can be automatically loaded to bring together all of the other \nparts instantly. This is considered more scalable than having to track the \nvarious dependencies for them and manually load modules or inject script tags.\n\nAny significantly non-trivial application should be built from modular\ncomponents. Going back to GMail, you could consider modules independent units of\nfunctionality that can exist on their own, so the chat feature for example. It's\nprobably backed by a chat module, however, depending on how complex that unit of\nfunctionality is, it may well have more granular sub-modules that it depends on.\nFor example, one could have a module simply to handle the use of emoticons which\ncan be shared across both chat and mail composition parts of the system.\n\nIn the architecture being discussed, modules have a **very limited knowledge**\nof what's going on in the rest of the system. Instead, we delegate this \nresponsibility to a mediator via a facade.\n\nThis is by design because if a module only cares about letting the system know\nwhen something of interest happens without worrying if other modules are running,\na system is capable of supporting adding, removing or replacing modules without \nthe rest of the modules in the system falling over due to tight coupling.\n\nLoose coupling is thus essential to this idea being possible. It facilitates\neasier maintainability of modules by removing code dependencies where possible. \nIn our case, modules should not rely on other modules in order to function \ncorrectly. When loose coupling is implemented effectively, its straight-forward \nto see how changes to one part of a system may affect another.\n\nIn JavaScript, there are several options for implementing modules including the\nwell-known module pattern and object literals. Experienced developers will \nalready be familiar with these and if so, please skip ahead to the section on \nCommonJS modules."
  },
  {
    "path": "_includes/translation/eng/06_the-module-pattern.md",
    "content": "##### The Module Pattern \n\nThe module pattern is a popular design that pattern that encapsulates 'privacy',\nstate and organization using closures. It provides a way of wrapping a mix of\npublic and private methods and variables, protecting pieces from leaking into \nthe global scope and accidentally colliding with another developer's interface. \nWith this pattern, only a public API is returned, keeping everything else within\nthe closure private.\n\nThis provides a clean solution for shielding logic doing the heavy lifting\nwhilst only exposing an interface you wish other parts of your application to \nuse. The pattern is quite similar to an immediately-invoked functional \nexpression\n([IIFE][3]) except that an object is returned rather than a function. \n\nIt should be noted that there isn't really a true sense of 'privacy' inside\nJavaScript because unlike some traditional languages, it doesn't have access \nmodifiers. Variables can't technically be declared as being public nor private \nand so we use function scope to simulate this concept. Within the module pattern,\nvariables or methods declared are only available inside the module itself thanks\nto closure. Variables or methods defined within the returning object however are\navailable to everyone.\n\nBelow you can see an example of a shopping basket implemented using the pattern\n. The module itself is completely self-contained in a global object called\n`basketModule`. The `basket` array in the module is kept private and so other\nparts of your application are unable to directly read it. It only exists with \nthe module's closure and so the only methods able to access it are those with \naccess to its scope (ie.`addItem()`, `getItem()` etc). \n\n    var basketModule = (function() {\n        var basket = []; //private\n        return { //exposed to public\n            addItem: function(values) {\n                basket.push(values);\n            },\n            getItemCount: function() {\n                return basket.length;\n            },\n            getTotal: function(){\n               var q = this.getItemCount(),p=0;\n                while(q--){\n                    p+= basket[q].price; \n                }\n                return p;\n            }\n        }\n    }());\n    \n\nInside the module, you'll notice we return an `object`. This gets automatically\nassigned to`basketModule` so that you can interact with it as follows: \n\n    //basketModule is an object with properties which can also be methods\n    basketModule.addItem({item:'bread',price:0.5});\n    basketModule.addItem({item:'butter',price:0.3});\n    \n    console.log(basketModule.getItemCount());\n    console.log(basketModule.getTotal());\n    \n    //however, the following will not work:\n    console.log(basketModule.basket);// (undefined as not inside the returned object)\n    console.log(basket); //(only exists within the scope of the closure)\n    \n\nThe methods above are effectively namespaced inside `basketModule`.\n\nFrom a historical perspective, the module pattern was originally developed by a\nnumber of people including[Richard Cornford][4] in 2003. It was later\npopularized by Douglas Crockford in his lectures and re-introduced by Eric \nMiraglia on the YUI blog.\n\nHow about the module pattern in specific toolkits or frameworks? \n\n**Dojo** \n\nDojo attempts to provide 'class'-like functionality through `dojo.declare`,\nwhich can be used for amongst other things, creating implementations of the \nmodule pattern. For example, if we wanted to declare`basket` as a module of the\n`store` namespace, this could be achieved as follows: \n\n    //traditional way\n    var store = window.store || {};\n    store.basket = store.basket || {};\n    \n    //using dojo.setObject\n    dojo.setObject(\"store.basket.object\", (function() {\n        var basket = [];\n        function privateMethod() {\n            console.log(basket);\n        }\n        return {\n            publicMethod: function(){\n                    privateMethod();\n            }\n        };\n    }()));\n    \n\nwhich can become quite powerful when used with `dojo.provide` and mixins. \n\n** YUI ** \n\nThe following example is heavily based on the original YUI module pattern\nimplementation by Eric Miraglia, but is relatively self-explanatory.\n\n    YAHOO.store.basket = function () {\n    \n        //\"private\" variables:\n        var myPrivateVar = \"I can be accessed only within YAHOO.store.basket .\";\n    \n        //\"private\" method:\n        var myPrivateMethod = function () {\n                YAHOO.log(\"I can be accessed only from within YAHOO.store.basket\");\n            }\n    \n        return {\n            myPublicProperty: \"I'm a public property.\",\n            myPublicMethod: function () {\n                YAHOO.log(\"I'm a public method.\");\n    \n                //Within basket, I can access \"private\" vars and methods:\n                YAHOO.log(myPrivateVar);\n                YAHOO.log(myPrivateMethod());\n    \n                //The native scope of myPublicMethod is store so we can\n                //access public members using \"this\":\n                YAHOO.log(this.myPublicProperty);\n            }\n        };\n    \n    }();\n    \n\n** jQuery ** \n\nThere are a number of ways in which jQuery code unspecific to plugins can be\nwrapped inside the module pattern. Ben Cherry previously suggested an \nimplementation where a function wrapper is used around module definitions in the\nevent of there being a number of commonalities between modules.\n\nIn the following example, a `library` function is defined which declares a new\nlibrary and automatically binds up the`init` function to `document.ready` when\nnew libraries (ie. modules) are created.\n\n    function library(module) {\n      $(function() {\n        if (module.init) {\n          module.init();\n        }\n      });\n      return module;\n    }\n    \n    var myLibrary = library(function() {\n       return {\n         init: function() {\n           /*implementation*/\n         }\n       };\n    }());"
  },
  {
    "path": "_includes/translation/eng/07_object-literal-notation.md",
    "content": "##### Object Literal Notation \n\nIn object literal notation, an object is described as a set of comma-separated\nname/value pairs enclosured in curly braces\n(`{}`). Names inside the object may be either strings or identifiers that are\nfollowed by a colon. There should be no comma used after the final name/value \npair in the object as this may result in errors.\n\nObject literals don't require instantiation using the `new` operator but\nshouldn't be used at the start of a statement as the opening`{` may be\ninterpreted as the beginning of a block. Below you can see an example of a \nmodule defined using object literal syntax. New members may be added to the \nobject using assignment as follows`myModule.property = 'someValue';`\n\nWhilst the module pattern is useful for many things, if you find yourself not\nrequiring specific properties or methods to be private, the object literal is a more than suitable alternative.\n\n    var myModule = {\n        myProperty : 'someValue',\n        //object literals can contain properties and methods.\n        //here, another object is defined for configuration\n        //purposes:\n        myConfig:{\n            useCaching:true,\n            language: 'en'   \n        },\n        //a very basic method\n        myMethod: function(){\n            console.log('I can haz functionality?');\n        },\n        //output a value based on current configuration\n        myMethod2: function(){\n            console.log('Caching is:' + (this.myConfig.useCaching)?'enabled':'disabled');\n        },\n        //override the current configuration\n        myMethod3: function(newConfig){\n            if(typeof newConfig == 'object'){\n               this.myConfig = newConfig;\n               console.log(this.myConfig.language); \n            }\n        }\n    };\n    \n    myModule.myMethod(); //I can haz functionality\n    myModule.myMethod2(); //outputs enabled\n    myModule.myMethod3({language:'fr',useCaching:false}); //fr\n\n\n[3]: http://benalman.com/news/2010/11/immediately-invoked-function-expression/\n[4]: http://groups.google.com/group/comp.lang.javascript/msg/9f58bd11bd67d937"
  },
  {
    "path": "_includes/translation/eng/08_commonjs-modules.md",
    "content": "### CommonJS Modules\n\nOver the last year or two, you may have heard about [CommonJS][5] - a volunteer\nworking group which designs, prototypes and standardizes JavaScript APIs. To \ndate they've ratified standards for modules and packages.The CommonJS AMD \nproposal specifies a simple API for declaring modules which can be used with \nboth synchronous and asynchronous script tag loading in the browser. Their \nmodule pattern is relatively clean and I consider it a reliable stepping stone \nto the module system proposed for ES Harmony (the next release of the JavaScript\nlanguage\n).\n\nFrom a structure perspective, a CommonJS module is a reusable piece of\nJavaScript which exports specific objects made available to any dependent code. \nThis module format is becoming quite ubiquitous as a standard module format for \nJS. There are plenty of great tutorials on implementing CommonJS modules, but at\na high-level they basically contain two primary parts: an`exports` object that\ncontains the objects a module wishes to make available to other modules and a\n`require` function that modules can use to import the exports of other modules. \n\n    /*\n    Example of achieving compatibility with AMD and standard CommonJS by putting\n    boilerplate around the standard CommonJS module format:\n    */\n    \n    (function(define){\n    define(function(require,exports){\n    // module contents\n     var dep1 = require(\"dep1\");\n     exports.someExportedFunction = function(){...};\n     //...\n    });\n    })(typeof define==\"function\"?define:function(factory){factory(require,exports)});\n    \n\nThere are a number of great JavaScript libraries for handling module loading in\nthe**CommonJS** module format, but my personal preference is RequireJS. A\ncomplete tutorial on RequireJS is outside the scope of this tutorial, but I can \nrecommend reading James Burke's ScriptJunkie post on it[here][6]. I know a\nnumber of people that also like Yabble.\n\nOut of the box, RequireJS provides methods for easing how we create static\nmodules with wrappers and it's extremely easy to craft modules with support for \nasynchronous loading. It can easily load modules and their dependencies this way\nand execute the body of the module once available.\n\nThere are some developers that however claim CommonJS modules aren't suitable\nenough for the browser. The reason cited is that they can't be loaded via a \nscript tag without some level of server-side assistance. We can imagine having a\nlibrary for encoding images as ASCII art which might export a`encodeToASCII`\nfunction. A module from this could resemble:\n\n    var encodeToASCII = require(\"encoder\").encodeToASCII;\n    exports.encodeSomeSource = function(){\n        //process then call encodeToASCII\n    }\n    \n\nThis type of scenario wouldn't work with a script tag because the scope isn't\nwrapped, meaning our`encodeToASCII` method would be attached to the `window`\n`require` wouldn't be as such defined and exports would need to be created for\neach module separately. A client-side library together with server-side \nassistance or a library loading the script with an XHR request using`eval()`\ncould however handle this easily.\n\nUsing RequireJS, the module from earlier could be rewritten as follows:\n\n    define(function(require, exports, module) {\n        var encodeToASCII = require(\"encoder\").encodeToASCII;\n        exports.encodeSomeSource = function(){\n                //process then call encodeToASCII\n        }\n    });\n    \n\nFor developers who may not rely on just using static JavaScript for their\nprojects, CommonJS modules are an excellent path to go down, but do spend some \ntime reading up on it. I've really only covered the tip of the ice berg but both\nthe CommonJS wiki and Sitepen have a number of resources if you wish to read \nfurther.\n\n\n[5]: http://commonjs.org\n[6]: http://msdn.microsoft.com/en-us/scriptjunkie/ff943568"
  },
  {
    "path": "_includes/translation/eng/09_the-facade-pattern.md",
    "content": "### The Facade Pattern \n\nNext, we're going to look at the facade pattern, a design pattern which plays a\ncritical role in the architecture being defined today.\n\nWhen you put up a facade, you're usually creating an outward appearance which\nconceals a different reality. The facade pattern provides a convenient**higher-\nlevel interface** to a larger body of code, hiding its true underlying\ncomplexity. Think of it as simplifying the API being presented to other \ndevelopers.\n\nFacades are a **structural pattern** which can often be seen in JavaScript\nlibraries and frameworks where, although an implementation may support methods \nwith a wide range of behaviors, only a 'facade' or limited abstract of these \nmethods is presented to the client for use.\n\nThis allows us to interact with the facade rather than the subsystem behind the\nscenes.\n\nThe reason the facade is of interest is because of its ability to hide\nimplementation-specific details about a body of functionality contained in \nindividual modules. The implementation of a module can change without the \nclients really even knowing about it.\n\nBy maintaining a consistent facade (simplified API), the worry about whether a\nmodule extensively uses dojo, jQuery, YUI, zepto or something else becomes \nsignificantly less important. As long as the interaction layer doesn't change, \nyou retain the ability to switch out libraries (eg. jQuery for Dojo) at a later \npoint without affecting the rest of the system.\n\nBelow is a very basic example of a facade in action. As you can see, our module\ncontains a number of methods which have been privately defined. A facade is then\nused to supply a much simpler API to accessing these methods:\n\n    var module = (function() {\n        var _private = {\n            i:5,\n            get : function() {\n                console.log('current value:' + this.i);\n            },\n            set : function( val ) {\n                this.i = val;\n            },\n            run : function() {\n                console.log('running');\n            },\n            jump: function(){\n                console.log('jumping');\n            }\n        };\n        return {\n            facade : function( args ) {\n                _private.set(args.val);\n                _private.get();\n                if ( args.run ) {\n                    _private.run();\n                }\n            }\n        }\n    }());\n    \n    \n    module.facade({run: true, val:10});\n    //outputs current value: 10, running\n    \n    \n\nand that's really it for the facade before we apply it to our architecture.\nNext, we'll be diving into the exciting mediator pattern. The core difference \nbetween the facade pattern and the mediator is that the facade (a structural \npattern) only exposes existing functionality whilst the mediator (a behavioral \npattern) can add functionality."
  },
  {
    "path": "_includes/translation/eng/10_the-mediator-pattern.md",
    "content": "### The Mediator Pattern\n\n \nThe mediator pattern is best introduced with a simple analogy - think of your\ntypical airport traffic control. The tower handles what planes can take off and \nland because all communications are done from the planes to the control tower, \nrather than from plane-to-plane. A centralized controller is key to the success \nof this system and that's really what a mediator is.\n\nMediators are used when the communication between modules may be complex, but\nis still**well defined**. If it appears a system may have too many\nrelationships between modules in your code, it may be time to have a central \npoint of control, which is where the pattern fits in.\n\nIn real-world terms, a mediator** encapsulates** how disparate modules **\ninteract** with each other by acting as an intermediary. The pattern also\npromotes loose coupling by preventing objects from referring to each other \nexplicitly - in our system, this helps to solve our module inter-dependency \nissues.\n\nWhat other advantages does it have to offer? Well, mediators allow for actions\nof each module to vary independently, so it’s extremely flexible. If you've \npreviously used the Observer (Pub/Sub) pattern to implement an event broadcast \nsystem between the modules in your system, you'll find mediators relatively easy\nto understand.\n\nLet's take a look at a high level view of how modules might interact with a\nmediator:\n\n![][7]\n\nConsider modules as publishers and the mediator as both a publisher and\nsubscriber. Module 1 broadcasts an event notifying the mediator something needs \nto done. The mediator captures this message and 'starts' the modules needed to \ncomplete this task Module 2 performs the task that Module 1 requires and \nbroadcasts a completion event back to the mediator. In the mean time, Module 3 \nhas also been started by the mediator and is logging results of any \nnotifications passed back from the mediator.\n\nNotice how at no point do any of the modules** directly communicate** with one\nanother. If Module 3 in the chain were to simply fail or stop functioning, the \nmediator could hypothetically 'pause' the tasks on the other modules, stop and \nrestart Module 3 and then continue working with little to no impact on the \nsystem. This level of decoupling is one of the main strengths the pattern has to\noffer.\n\nTo review, the advantages of the mediator are that:\n\nIt decouples modules by introducing an intermediary as a central point of\ncontrol.It allows modules to broadcast or listen for messages without being \nconcerned with the rest of the system. Messages can be handled by any number of \nmodules at once.\n\nIt is typically significantly more easy to add or remove features to systems\nwhich are loosely coupled like this.\n\nAnd its disadvantages: \n\nBy adding a mediator between modules, they must always communicate indirectly.\nThis can cause a very minor performance drop - because of the nature of loose \ncoupling, its difficult to establish how a system might react by only looking at\nthe broadcasts. At the end of the day, tight coupling causes all kinds of \nheadaches and this is one solution.\n\n** Example:** This is a possible implementation of the mediator pattern based\non previous work by[@rpflorence][8]\n\n    var mediator = (function(){\n        var subscribe = function(channel, fn){\n            if (!mediator.channels[channel]) mediator.channels[channel] = [];\n            mediator.channels[channel].push({ context: this, callback: fn });\n            return this;\n        },\n    \n        publish = function(channel){\n            if (!mediator.channels[channel]) return false;\n            var args = Array.prototype.slice.call(arguments, 1);\n            for (var i = 0, l = mediator.channels[channel].length; i \n    \n    \n    \n**Example:** Here are two sample uses of the implementation from above. It's effectively managed publish/subscribe:\n    \n    \n    \n    //Pub/sub on a centralized mediator\n    \n    mediator.name = \"tim\";\n    mediator.subscribe('nameChange', function(arg){\n            console.log(this.name);\n            this.name = arg;\n            console.log(this.name);\n    });\n    \n    mediator.publish('nameChange', 'david'); //tim, david\n    \n    \n    //Pub/sub via third party mediator\n    \n    var obj = { name: 'sam' };\n    mediator.installTo(obj);\n    obj.subscribe('nameChange', function(arg){\n            console.log(this.name);\n            this.name = arg;\n            console.log(this.name);\n    });\n    \n    obj.publish('nameChange', 'john'); //sam, john\n\n\n[7]: img/chart4a.jpg\n[8]: https://github.com/rpflorence"
  },
  {
    "path": "_includes/translation/eng/11_applying-the-facade-abstraction-of-the-core.md",
    "content": "### **Applying The Facade: Abstraction Of The Core**\n\nIn the architecture suggested:\n\nA facade serves as an **abstraction** of the application core which sits between\nthe mediator and our modules - it should ideally be the **only** other part of\nthe system modules are aware of. \n\n\n\n\nThe responsibilities of the abstraction include ensuring a **consistent\ninterface** to these modules is available at all times. This closely resembles\nthe role of the **sandbox controller** in the excellent architecture first\nsuggested by Nicholas Zakas.\n\n\nComponents are going to communicate with the mediator through the facade so it\nneeds to be **dependable**. When I say 'communicate', I should clarify that as\nthe facade is an abstraction of the mediator which will be listening out for\nbroadcasts from modules that will be relayed back to the mediator.\n\n\nIn addition to providing an interface to modules, the facade also acts as\na security guard, determining which parts of the application a module may\naccess. Components only call **their own** methods and shouldn't be able to\ninterface with anything they don't have permission to. For example, a module\nmay broadcast dataValidationCompletedWriteToDB. The idea of a security check\nhere is to ensure that the module has permissions to request database-write\naccess. What we ideally want to avoid are issues with modules accidentally\ntrying to do something they shouldn't be.\n\n\nTo review in short, the mediator remains a type of pub/sub manager but is only\npassed interesting messages once they've cleared permission checks by the\nfacade."
  },
  {
    "path": "_includes/translation/eng/12_applying-the-mediator-the-application-core.md",
    "content": "### **Applying the Mediator: The Application Core**\n\n\nThe mediator plays the role of the application core. We've briefly touched on\nsome of its responsibilities but lets clarify what they are in full. \n\n\n\nThe core's primary job is to manage the module **lifecycle. **When the core\ndetects an** interesting message** it needs to decide how the application\nshould react - this effectively means deciding whether a module or set of\nmodules needs to be **started** or** stopped**. \n\nOnce a module has been started, it should ideally execute **automatically**.\nIt's not the core's task to decide whether this should be when the DOM is ready\nand there's enough scope in the architecture for modules to make such decisions\non their own. \n\nYou may be wondering in what circumstance a module might need to be 'stopped'\n- if the application detects that a particular module has failed or is\nexperiencing significant errors, a decision can be made to prevent methods in\nthat module from executing further  so that it may be restarted. The goal here\nis to assist in reducing disruption to the user experience.\n\nIn addition, the core should enable **adding or removing** modules without\nbreaking anything. A typical example of where this may be the case is\nfunctionality which may not be available on initial page load, but is\ndynamically loaded based on expressed user-intent eg. going back to our GMail\nexample, Google could keep the chat widget collapsed by default and only\ndynamically load in the chat module(s) when a user expresses an interest in\nusing that part of the application. From a performance optimization perspective,\nthis may make sense.\n\nError management will also be handled by the application core. In addition to\nmodules broadcasting messages of interest they will also broadcast any errors\nexperienced which the core can then react to accordingly (eg. stopping modules,\nrestarting them etc).It's important that as part of a decoupled architecture\nthere to be enough scope for the introduction of new or better ways of handling\nor displaying errors to the end user without manually having to change each\nmodule. Using publish/subscribe through a mediator allows us to achieve this."
  },
  {
    "path": "_includes/translation/eng/13_tying-it-all-together.md",
    "content": "### **Tying It All Together**\n\n\n*   **Modules** contain specific pieces of functionality for your application.\n    They publish notifications informing the application whenever something \n    interesting happens - this is their primary concern. As I'll cover in the FAQs, \n    modules can depend on DOM utility methods, but ideally shouldn't depend on any \n    other modules in the system. They should not be concerned with:\n   \n    \n    *   what objects or modules are subscribing to the messages they publish\n    *   where these objects are based (whether this is on the client or server\n        )\n    *   how many objects subscribe to notifications\n\n**![][9]**\n\n*   **The Facade** abstracts the core to avoid modules touching it directly. It\n    subscribes to interesting events (from modules) and says 'Great! What happened? \n    Give me the details!'. It also handles module security by checking to ensure the\n    module broadcasting an event has the necessary permissions to pass such events \n    that can be accepted.\n\n**![][10]**\n\n*   **The Mediator (Application Core)** acts as a 'Pub/Sub' manager using the\n    mediator pattern. It's responsible for module management and starts/stops \n    modules as needed. This is of particular use for dynamic dependency loading and \n    ensuring modules which fail can be centrally restarted as needed.\n   \n**![][11]**\n\nThe result of this architecture is that modules (in most cases) are\ntheoretically no longer dependent on other modules. They can be easily tested \nand maintained on their own and because of the level of decoupling applied, \nmodules can be picked up and dropped into a new page for use in another project \nwithout significant additional effort. They can also be dynamically added or \nremoved without the application falling over.\n\n\n[9]: img/chart1a.gif\n[10]: img/chart2a.gif\n[11]: img/chart3a.gif"
  },
  {
    "path": "_includes/translation/eng/14_beyond-pub-sub-automatic-event-registration.md",
    "content": "### Beyond Pub/Sub: Automatic Event Registration\n\nAs previously mentioned by Michael Mahemoff, when thinking about large-scale\nJavaScript, it can be of benefit to exploit some of the more dynamic features of\nthe language. You can read more about some of the concerns highlighted on \nMichael's[G+][12] page, but I would like to focus on one specifically -\nautomatic event registration (AER\n).\n\nAER solves the problem of wiring up subscribers to publishers by introducing a\npattern which auto-wires based on naming conventions. For example, if a module \npublishes an event called`messageUpdate`, anything with a `messageUpdate`\nmethod would be automatically called.\n\nThe setup for this pattern involves registering all components which might\nsubscribe to events, registering all events that may be subscribed to and \nfinally for each subscription method in your component-set, binding the event to\nit. It's a very interesting approach which is related to the architecture \npresented in this post, but does come with some interesting challenges.\n\nFor example, when working dynamically, objects may be required to register\nthemselves upon creation. Please feel free to check out Michael's[post][13] on\nAER as he discusses how to handle such issues in more depth.\n\n\n[12]: https://plus.google.com/106413090159067280619/posts/hDZkVrDXZR6\n[13]: http://softwareas.com/automagic-event-registration"
  },
  {
    "path": "_includes/translation/eng/15_frequently-asked-questions.md",
    "content": "### Frequently Asked Questions\n\n#### Q: Is it possible to avoid implementing a sandbox or facade altogether?\n\nA: Although the architecture outlined uses a facade to implement security\nfeatures, it's entirely possible to get by using a mediator and pub/sub to \ncommunicate events of interest throughout the application without it. This \nlighter version would offer a similar level of decoupling, but ensure you're \ncomfortable with modules directly touching the application core (mediator) if \nopting for this variation.\n\n#### Q: You've mentioned modules not having any dependencies. Does this include\ndependencies such as third party libraries (eg. jQuery?\n)\n\nA: I'm specifically referring to dependencies on other modules here. What some\ndevelopers opting for an architecture such as this opt for is actually \nabstracting utilities common to DOM libraries -eg. one could have a DOM utility \nclass for query selectors which when used returns the result of querying the DOM\nusing jQuery (or, if you switched it out at a later point, Dojo). This way, \nalthough modules still query the DOM, they aren't directly using hardcoded \nfunctions from any particular library or toolkit. There's quite a lot of \nvariation in how this might be achieved, but the takeaway is that ideally core \nmodules shouldn't depend on other modules if opting for this architecture.\n\nYou'll find that when this is the case it can sometimes be more easy to get a\ncomplete module from one project working in another with little extra effort. I \nshould make it clear that I fully agree that it can sometimes be significantly \nmore sensible for modules to extend or use other modules for part of their \nfunctionality, however bear in mind that this can in some cases increase the \neffort required to make such modules 'liftable' for other projects.\n\n#### Q: I'd like to start using this architecture today. Is there any\nboilerplate code around I can work from?\n\nA: I plan on releasing a free boilerplate pack for this post when time permits\n, but at the moment, your best bet is probably the\n'[Writing Modular JavaScript][14]' premium tutorial by Andrew Burgees (for\ncomplete disclosure, this is a referral link as any credits received are re-\ninvested into reviewing material before I recommend it to others). Andrew's pack\nincludes a screencast and code and covers most of the main concepts outlined in \nthis post but opts for calling the facade a 'sandbox', as per Zakas. There's \nsome discussion regarding just how DOM library abstraction should be ideally \nimplemented in such an architecture - similar to my answer for the second \nquestion, Andrew opts for some interesting patterns on generalizing query \nselectors so that at most, switching libraries is a change that can be made in a\nfew short lines. I'm not saying this is the right or best way to go about this, \nbut it's an approach I personally also use.\n\n#### Q: If the modules need to directly communicate with the core, is this\npossible?\n\nA: As Zakas has previously hinted, there's technically no reason why modules\nshouldn't be able to access the core but this is more of a best practice than \nanything. If you want to strictly stick to this architecture you'll need to \nfollow the rules defined or opt for a looser architecture as per the answer to \nthe first question.\n\n\n[14]: http://bit.ly/orGVOL"
  },
  {
    "path": "_includes/translation/eng/16_credits.md",
    "content": "### Credits\n\nThanks to Nicholas Zakas for his original work in bringing together many of the\nconcepts presented today; Andrée Hansson for his kind offer to do a technical \nreview of the post (as well as his feedback that helped improve it); Rebecca \nMurphey, Justin Meyer, John Hann, Peter Michaux, Paul Irish and Alex Sexton, all\nof whom have written material related to the topics discussed in the past and \nare a constant source of inspiration for both myself and others."
  },
  {
    "path": "_includes/translation/rus/00_intro.md",
    "content": "В этой книге мы обсудим набор паттернов, который поможет вам в создании \nбольших масштабируемых JavaScript-приложений. Материал книги основан на моем\nодноименном докладе, впервые прочитанном на конференции «LondonJS», и\nвдохновленном [предшествующей ему работой][1] Николаса Закаса.\n\n### Кто я и почему я решил об этом написать?\n\nМеня зовут Эдди Османи. Сейчас я работаю JavaScript- и UI-разработчиком в AOL.\nЯ занимаюсь планированием и написанием фронтенд-архитектуры для следующего\nпоколения наших пользовательских приложений. Эти приложения весьма сложны. Они\nнуждаются в архитектуре, позволяющей, с одной стороны легко их масштабировать,\nа с другой достаточно легко использовать повторно их модули. Также я занимаюсь\nразработкой шаблонов, которые можно применять в разработке приложений подобного\nмасштаба настолько качественно, насколько это вообще возможно.\n\nКроме того, я рассматриваю себя как евангелиста шаблонов проектирования (хотя\nесть много экспертов, разбирающихся в этом лучше меня). В прошлом я написал книгу \n«[Essential JavaScript Design Patterns][2]», а сейчас я занимаюсь написанием более \nподробного продолжения этой книги.\n\n\n### Могу ли я уместить эту книгу в 140 символов?\n\nЯ уместил эту статью в один твит, на случай, если у вас совсем мало времени:\n\nМеньше связанности: используйте паттерны «модуль», «фасад» и «медиатор». Модули\nобщаются через медиатор, а фасад обеспечивает безопасность.\n{:class=\"message\"}\n\n\n[1]: http://www.slideshare.net/nzakas/scalable-javascript-application-architecture\n[2]: http://addyosmani.com/resources/essentialjsdesignpatterns/book/\n"
  },
  {
    "path": "_includes/translation/rus/01_what-exactly-is-a-large-javascript-application.md",
    "content": "<!-- ### Что из себя представляет «большое» JavaScript приложение? -->\n\nПеред тем как я начну, давайте постараемся определить, что именно мы имеем \nв виду, когда говорим о больших JavaScript-приложениях. Этот вопрос\nя считаю своего рода вызовом опытным разработчикам, и ответы на него,\nсоответственно, получаются очень субъективными.\n\nРади эксперимента я предложил нескольким среднестатистическим разработчикам\nдать собственное определение этому термину. Один из разработчиков сказал, что\nречь идет о «JavaScript-приложениях, состоящих из более чем 100 000 \nстрок кода», когда другой определил что большое приложение «содержит больше\nчем 1 МБ JavaScript». Я расстроил храбрецов — оба этих варианта\nдалеки от истины. Количество кода не всегда коррелирует со сложностью приложения.\n100 000 строк легко могут оказаться самым ничем не примечательным простым кодом.\n\nЯ не знаю, подходит ли мое собственное определение к любому случаю, но я верю,\nчто оно находится ближе всего к тому, что действительно представляет из себя\nбольшое JavaScript-приложение.\n\n{:class=\"message\"}\nЯ думаю, что большие JavaScript-приложения решают нетривиальные задачи,\nа поддержка таких приложений требует от разработчика серьезных усилий.\nПри этом, большая часть работы по манипуляции данными и их отображению ложится\nна браузер.\n\nЯ думаю, что последняя часть определения — самая важная.\n"
  },
  {
    "path": "_includes/translation/rus/02_lets-review-your-current-architecture.md",
    "content": "<!-- ### Давайте обсудим вашу существующую архитектуру -->\n\n{:.message}\nРаботая над большим JavaScript-приложением, не забывайте уделять **достаточное\nколичество времени** на планирование изначальной архитектуры, к которой такие \nприложения очень чувствительны. Большие приложения обычно представляют\nиз себя очень сложные системы, гораздо более сложные, чем вы представляете\nсебе изначально.\n\nЯ должен подчеркнуть значение этой разницы — я видел разработчиков, которые,\nсталкиваясь с большими приложениями, делали шаг назад и говорили: «Хорошо,\nу меня есть несколько идей, которые хорошо показали себя в моем предыдущем\nпроекте среднего масштаба. Думаю, они точно сработают и для чего-то большего,\nне так ли?». Конечно, до какого-то момента это может быть так, но, пожалуйста,\nне принимайте это как должное — по большей части большие приложения имеют ряд\nдостаточно серьезных проблем, с которыми нужно считаться. Ниже я приведу\nнесколько доводов в пользу того, почему вам стоит уделить немного больше времени \nпланированию архитектуры своего приложения, и чем вам это будет полезно\nв долгосрочной перспективе.\n\nБольшинство JavaScript-разработчиков в архитектуре своих приложений обычно\nиспользует различные комбинации следующих компонентов:\n\n*   виджеты\n*   модели\n*   представления\n*   контроллеры\n*   шаблоны\n*   библиотеки\n*   ядро приложения.\n\n{:class=\"message\"}\n**Ссылки по теме:**  \n[Ребекка Мёрфи — Создание архитектуры JavaScript-приложений][1]  \n[Питер Мишо — MVC архитектура для JavaScript-приложений][2]  \n[StackOverflow — Дискуссия о современных MVC-фреймворках][3]  \n[Дуг Найнер — Поддерживаемые плагины и фабрика виджетов][4]  \n\n\nВероятно, вы выносите различные функции ваших приложений в отдельные модули,\nлибо используете какие-нибудь другие шаблоны проектирования для подобного\nразделения. Это очень хорошо, но здесь есть ряд потенциальных проблем,\nс которыми вы можете столкнуться при таком подходе.\n\n\n### 1. Готова ли ваша архитектура к повторному использованию кода уже сейчас?\n\nМогут ли отдельные модули использоваться самостоятельно? Достаточно ли они\nавтономны для этого? Мог бы я прямо сейчас взять один из модулей вашего большого \nприложения, просто поместить его на новую веб-страницу, а затем, тут же, начать\nего использовать? У вас может возникнуть вопрос: «Действительно ли это так\nнеобходимо?», но, как бы то ни было, я надеюсь, что вы думаете о будущем. Что, \nесли ваша компания начнет создавать все больше и больше нетривиальных\nприложений, которые будут иметь некоторую общую функциональность? Если кто-то\nскажет: «Нашим пользователям очень нравится использовать модуль чата в нашем\nemail-клиенте, почему бы нам не добавить этот модуль к нашему новому приложению для\nсовместной работы с документами?», будет ли это возможно, если мы не уделим\nдолжного внимания контролю кода?\n\n\n### 2. Сколько модулей в вашей системе зависит от других модулей?\n\nНасколько сильно связаны ваши модули? Перед тем, как я погружусь в объяснения\nо том, как важна слабая связанность модулей, я должен отметить, что не всегда есть\nвозможность создавать модули, не имеющие абсолютно никаких зависимостей\nв системе. К примеру, одни модули могут расширять функции других, уже существующих.\nЭта тема, скорее всего, относится к группировке модулей на основе некоторой\nфункциональности. Отдельные наборы модулей должны работать в вашем приложении без\nбольшого количества зависимостей, чтобы наличие или загрузка других модулей\nне влияла на их работоспособность.\n\n\n### 3. Сможет ли ваше приложение работать дальше, если его отдельная часть сломается?\n\nЕсли вы разрабатываете приложения, подобные Gmail, и ваш webmail-модуль (или \nгруппа модулей) перестанет работать из-за ошибки, то это не должно заблокировать\nпользовательский интерфейс или помешать пользователям использовать другие части\nвашего приложения, к примеру, такие как чат. В то же время, как было сказано\nраньше, было бы идеально, если бы модули могли работать и за пределами вашей\nархитектуры. В моей лекции я упоминал динамические зависимости — возможность\nзагружать модули, исходя из определенных действий пользователя. К примеру,\nребята из Gmail могли бы изначально держать чат закрытым, не загружая его\nкод при открытии страницы. А в тот момент, когда пользователь решит\nвоспользоваться им — соответствующий модуль будет динамически загружен и\nвыполнен. В идеальном случае хотелось бы выполнить это без каких-то негативных\nэффектов в вашем приложении.\n\n\n### 4. Насколько легко вы сможете тестировать отдельные модули?\n\nКогда вы работаете над масштабными системами, есть вероятность, что\nразличные части этой системы будут использовать миллионы пользователей.\nВполне вероятно, что эти части будут использоваться не только в предусмотренных\nвами ситуациях. В конечном счете, код может использоваться повторно в огромном\nколичестве различных окружений, и важно, чтобы модули были достаточно\nпротестированы. Тестировать модули необходимо и внутри архитектуры, для которой\nон был изначально разработан, и снаружи. По моему мнению, это дает наибольшую\nгарантию того, что модуль не сломается при попадании в другую систему.\n\n[1]: http://rmurphey.com/blog/2010/08/27/code-org-take-2-structuring-javascript-applications/\n[2]: http://michaux.ca/articles/mvc-architecture-for-javascript-applications\n[3]: http://stackoverflow.com/questions/5112899/knockout-js-vs-backbone-js-vs\n[4]: http://msdn.microsoft.com/en-us/scriptjunkie/ff706600\n"
  },
  {
    "path": "_includes/translation/rus/03_think-long-term.md",
    "content": "<!-- ### Думай о будущем -->\n\nВ процессе создания архитектуры большого приложения, очень важно думать о будущем.\nНе только о том, что будет через месяц или через год, но и о том, что будет после\nэтого. Что может измениться? Конечно, невозможно достаточно точно предсказать\nкак ваше приложение будет развиваться, но, вне всякого сомнения, имеет смысл\nподумать об этом. Думаю, что найдется хотя бы один специфичный аспект вашего\nприложения, о котором стоит поразмыслить.\n\nРазработчики зачастую слишком сильно связывают манипуляцию с DOM-элементами и\nостальные части приложения, даже если до этого они не поленились разделить\nбизнес-логику на модули. Подумайте, почему в долгосрочной перспективе это\nможет быть плохой идеей?\n\nОдин из слушателей моей лекции предположил, что такая архитектура негибка, и может\nне работать в будущем. Это действительно так, но есть другая проблема, игнорирование\nкоторой окажет еще более негативный эффект.\n\n{:class=\"message\"}\nВ будущем, вы можете принять решение о **замене** Dojo, jQuery, Zepto или YUI на\nчто-нибудь совершенно иное. Причиной такого перехода может быть производительность,\nбезопасность или дизайн. Это может стать серьезной проблемой, потому как библиотеки\nне предусматривают простой замены. Цена замены библиотеки будет высокой, если ваше\nприложение тесно с ней связано.\n\nЕсли вы используете Dojo (как многие слушатели на моей лекции), вы можете\nбыть уверены, что нет ничего лучше, на что имело бы смысл сейчас перейти. Но\nможете ли вы быть уверены, что в течении двух-трех лет не появится что-нибудь,\nчто вызовет у вас интерес? Что-нибудь, на что вы можете решить перейти.\n\nТакое решение может быть достаточно простым для небольших проектов, но для\nбóльших приложений гибкая архитектура может принести значительную пользу как в\nфинансовом плане, так и с точки зрения экономии времени благодаря тому, что\nеё можно поддерживать **не** заботясь об используемых библиотеках.\n\nПодводя итог, взгляните на вашу архитектуру сейчас. Сможете ли вы сегодня сменить\nвашу библиотеку на любую другую, не переписывая при этом ваше приложение\nполностью? Если это не так, то вам стоит продолжить чтение. Я думаю, что\nв архитектуре, которую мы обсуждаем, вы найдёте кое-что интересное. \n\nНекоторые из известных JavaScript-разработчиков раньше уже излагали проблемы,\nо которых я написал выше. Вот три ключевых цитаты, которыми я бы хотел поделиться\nс вами.\n\n{:class=\"message\"}\n«Секрет создания больших приложений в том, чтобы никогда не создавать больших\nприложений. Разбейте ваши приложения на маленькие части, а затем собирайте из\nэтих маленьких тестируемых фрагментов ваше большое приложение»\n**Джастин Майер, автор «JavaScriptMVC»**\n\n{:class=\"message\"}\n«Секрет в том, чтобы признаться самому себе с самого начала, что вы понятия\nне имеете о том, как ваше приложение будет развиваться. Когда вы согласитесь\nс этим, вы начнете проектировать систему основываясь на защите. Вы определите\nключевые области, в которых, вероятнее всего будут происходить изменения. Очень\nчасто это не составляет труда, если потратить на это немного времени. К примеру,\nвы ожидаете, что любая часть приложения, которая взаимодействует с другой\nсистемой — это потенциальная мишень для изменений. И вы понимаете, что здесь вам\nпонадобится абстракция».  \n**Николас Закас, автор книги «Высокопроизводительный JavaScript**\n\nИ последняя, но тоже очень важная цитата:\n\n{:class=\"message\"}\n«Чем сильнее компоненты связаны между собой, тем меньше возможностей для их\nповторного использования, тем сложнее вносить изменения, не получая при этом различных\nпобочных эффектов в самых неожиданных местах»\n**Ребекка Мёрфи, автор книги «Фундаментальные основы jQuery»**\n\nЭти принципы необходимы для создания архитектуры, способной выдержать испытание\nвременем. Важно всегда помнить о них.\n\n\n"
  },
  {
    "path": "_includes/translation/rus/04_brainstorming.md",
    "content": "<!-- ### Мозговой штурм -->\n\nДавайте немного подумаем, что мы хотим получить.\n\n{:class=\"message\"}\nМы хотим получить слабосвязанную архитектуру с функциональностью, разделенную\nна **независимые модули**, которые, в идеале, не должны иметь зависимостей друг\nот друга. Когда случается что-то интересное, модули **сообщают** об этом другим\nчастям приложения, а промежуточный слой интерпретирует их сообщения и необходимым\nобразом реагирует на них.\n\nНапример, у нас есть JavaScript-приложение, отвечающее за онлайн-пекарню. Одно из\nинтересных нам сообщений может быть таким: «Партия из 42 батонов готова к доставке».\n\nМы используем отдельный слой для обработки сообщений модулей, чтобы а) модули\nне взаимодействовали напрямую с ядром, б) модули не взаимодействовали напрямую\nдруг с другом. Это помогает не допустить падения приложения из-за различных\nошибок внутри одного из модулей. Также это позволяет нам перезапускать модули\nесли они вдруг перестали работать из-за какой-нибудь ошибки.\n\nЕще один момент — безопасность. На самом деле, немногие из нас заботятся\nо внутренней безопасности своих приложений в должной мере. Когда мы определяем\nструктуру приложения, мы говорим себе, что мы достаточно умны для того, чтобы\nпонимать что в нашем коде должно быть публичным, а что приватным.\n\nХорошо, но поможет ли это если вы решите определить что именно разрешено\nмодулю выполнять в системе? К примеру, в моем приложении, ограничив доступ из\nмодуля веб-чата к интерфейсу модуля администрирования, я смогу уменьшить шансы\nна успешное использование XSS уязвимостей, которые я не смог найти в виджете.\nМодули не должны иметь доступ ко всему. Вероятно, в вашей существующей\nархитектуре они могут использовать любые части системы, но уверены ли вы, что\nэто действительно необходимо?\n\nПромежуточный слой, проверяющий имеет ли модуль доступ к определенной части\nвашего фреймворка, обеспечивает большую безопасность вашей системы. Фактически\nэто значит что модули могут взаимодействовать только с теми компонентами \nсистемы, с которыми мы разрешим им взаимодействовать.\n\n\n### Архитектура, которую я предлагаю вам\n\nАрхитектура, о которой мы говорим, представляет из себя комбинацию трех\nизвестных шаблонов проектирования: модуль, фасад и медиатор.\n\nВ отличии от традиционной модели, в которой модули напрямую взаимодействуют друг с\nдругом, в этой слабосвязанной архитектуре модули всего лишь публикуют события (в\nидеале, не зная о других модулях в системе). Медиатор используется для подписки на\nсообщения от модулей и для решения, каким должен быть ответ на уведомление. Паттерн\nфасад используется для ограничения действий разрешенных модулям.\n\nВ следующих главах я более детально расскажу о каждом из этих шаблонов\nпроектирования.\n"
  },
  {
    "path": "_includes/translation/rus/05_module-theory.md",
    "content": "<!-- ### Теория модулей -->\n\nВероятно, в каком-то виде вы уже используете модули в своей существующей\nархитектуре. Если это не так, то в этой главе я покажу вам, как они устроены.\n\n{:class=\"message\"}\nМодули — это **целая** часть любой хорошей архитектуры приложения. Обычно\nмодули выполняют одну определенную задачу в более крупных системах и могут быть\nвзаимозаменяемы.\n\nВ некоторых реализациях модули могут иметь свои собственные зависимости, которые\nбудут загружены автоматически, собирая вместе таким образом все компоненты\nсистемы. Такой подход считается более масштабируемым, в отличие от ручной\nзагрузки модулей или подстановки тега `script`.\n\nКаждое нетривиальное приложение должно создаваться из модульных компонентов.\nРассмотрим GMail: вы можете рассматривать модули, как независимые единицы\nфункциональности, которые могут и должны существовать сами по себе; возьмём к\nпримеру чат. Скорее всего он основан на своём отдельном модуле чата, но так как\nэтот модуль скорее всего очень сложный, то он вероятно состоит из более мелких\nвспомогательных модулей. Например, один из таких модулей мог бы отвечать за\nиспользование смайликов и он же мог бы использоваться не только в чате, но также\nи в почте.\n\n{:class=\"message\"}\nВ рассматриваемой архитектуре модули имеют **очень ограниченные знания** о том, что\nпроисходит в других частях системы. Вместо этого мы делегируем ответственность\nмедиатору и фасаду.\n\nВ этом и заключается идея нашей архитектуры — если модуль заботится исключительно\nо том, чтобы уведомить систему об интересующих ее происшествиях, и не волнуется\nзапущены ли другие модули, то система может добавлять, удалять или заменять одни\nмодули, не ломая при этом другие, что было бы невозможно при сильной связанности.\n\nСлабая связанность — необходимое условие для того, чтобы такая идея была возможна.\nОна делает поддержку модулей проще, удаляя зависимости в коде там, где это возможно.\nВ вашем случае, одни модули должны работать корректно вне зависимости от того в\nкаком порядке загрузились другие модули. Когда слабая связанность реализована\nэффективно, становится очевидно, как изменения в одной части системы влияют на другие ее части.\n\nВ JavaScript есть несколько способов реализации модулей, включая\nшаблон «Модуль» и Object Literal (литеральная запись объекта `var obj = {};`).\nОпытные разработчики должно быть уже знакомы с ними. Если это так, то вы можете\nпропустить следующую главу и  перейти сразу к главе «Модули CommonJS».\n"
  },
  {
    "path": "_includes/translation/rus/06_the-module-pattern.md",
    "content": "<!-- ##### Паттерн «Модуль» -->\n\n«Модуль» — это популярная реализация паттерна, инкапсулирующего приватную\nинформацию, состояние и структуру, используя замыкания. Это позволяет оборачивать\nпубличные и приватные методы и переменные в модули, и предотвращать их\nпопадание в глобальный контекст, где они могут конфликтовать с интерфейсами\nдругих разработчиков. Паттерн «модуль» возвращает только публичную часть API,\nоставляя всё остальное доступным только внутри замыканий.\n\nЭто хорошее решение для того, чтобы скрыть внутреннюю логику от посторонних глаз и\nпроизводить всю тяжелую работу исключительно через интерфейс, который вы определите\nдля использования в других частях вашего приложения. Этот паттерн очень похож на\nнемедленно-вызываемые функции ([IIFE][3]), за тем исключением, что модуль вместо\nфункции, возвращает объект.\n\nВажно заметить, что в JavaScript нет настоящей приватности. В отличии от некоторых\nтрадиционных языков, он не имеет модификаторов доступа. Переменные технически\nне могут быть объявлены как публичные или приватные, и нам приходится использовать\nобласть видимости для того, чтобы эмулировать эту концепцию. Благодаря замыканию,\nобъявленные внутри модуля переменные и методы доступны только изнутри этого модуля.\nПеременные и методы, объявленные внутри объекта, возвращаемого модулем, будут\nдоступны всем.\n\nНиже вы можете увидеть корзину покупок, реализованную с помощью паттерна «модуль».\nПолучившийся компонент находится в глобальном объекте `basketModule`, и содержит\nвсё, что ему необходимо. Находящийся внутри него, массив `basket` приватный,\nи другие части вашего приложения не могут напрямую взаимодействовать с ним. \nМассив `basket` существует внутри замыкания, созданного модулем, и\nвзаимодействовать с ним могут только методы, находящиеся в том же контексте\n(например, `addItem()`, `getItem()`). \n\n\n{% highlight javascript %}\nvar basketModule = (function() {\n  var basket = []; // приватная переменная\n    return { // методы доступные извне\n        addItem: function(values) {\n            basket.push(values);\n        },\n        getItemCount: function() {\n            return basket.length;\n        },\n        getTotal: function() {\n           var q = this.getItemCount(),p=0;\n            while(q--){\n                p+= basket[q].price; \n            }\n            return p;\n        }\n    }\n}());\n{% endhighlight %}\n\nВнутри модуля, как вы заметили, мы возвращаем объект. Этот объект автоматически\nприсваивается переменной `basketModule`, так что с ним можно взаимодействовать\nследующим образом:\n\n{% highlight javascript %}\n// basketModule - это объект со свойствами, которые могут также быть и методами:\nbasketModule.addItem({item:'bread', price:0.5});\nbasketModule.addItem({item:'butter', price:0.3});\n\nconsole.log(basketModule.getItemCount());\nconsole.log(basketModule.getTotal());\n\n// А следующий ниже код работать не будет:\nconsole.log(basketModule.basket); // undefined потому что не входит в возвращаемый объект\nconsole.log(basket); // массив доступен только из замыкания\n{% endhighlight %}\n\n\nМетоды выше фактически помещены в неймспейс `basketModule`.\n\nИсторически, паттерн «модуль» был разработан в 2003 году группой людей, в число\nкоторых входил [Ричард Корнфорд][4]. Позднее этот паттерн был популяризован\nДугласом Крокфордом в его лекциях, и открыт заново в блоге YUI благодаря Эрику \nМирагилиа.\n\nДавайте посмотрим на реализацию «модуля» в различных библиотеках и фреймворках.\n\n**Dojo** \n\nDojo старается обеспечивать поведение похожее на классы с помощью `dojo.declare`,\nкоторый, кроме создания «модулей», также используется и для других вещей.\nДавайте попробуем, для примера, определить `basket` как модуль внутри неймспейса\n`store`:\n\n{% highlight javascript %}\n\n// традиционный способ\nvar store = window.store || {};\nstore.basket = store.basket || {};\n\n// с помощью dojo.setObject\ndojo.setObject(\"store.basket.object\", (function() {\n    var basket = [];\n    function privateMethod() {\n        console.log(basket);\n    }\n    return {\n        publicMethod: function() {\n            privateMethod();\n        }\n    };\n}()));\n\n{% endhighlight %}\n\nЛучшего результата можно добиться, используя `dojo.provide` и миксины.\n\n\n**YUI** \n\nСледующий код, по большей части, основан на примере реализации паттерна\n«модуль» в фреймворке YUI, разработанным Эриком Миргалиа, но более\nсамодокументирован.\n\n{% highlight javascript %}\n\nYAHOO.store.basket = function () {\n\n    // приватная переменная:\n    var myPrivateVar = \"Ко мне можно получить доступ только из YAHOO.store.basket.\";\n\n    // приватный метод:\n    var myPrivateMethod = function() {\n        YAHOO.log(\"Я доступен только при вызове из YAHOO.store.basket\");\n    }\n\n    return {\n        myPublicProperty: \"Я - публичное свойство\",\n        myPublicMethod: function() {\n            YAHOO.log(\"Я - публичный метод\");\n\n            // Будучи внутри корзины я могу получить доступ к приватным переменный и методам:\n            YAHOO.log(myPrivateVar);\n            YAHOO.log(myPrivateMethod());\n\n            // Родной контекст метода myPublicMethod сохранён\n            // поэтому мы имеет доступ к this\n            YAHOO.log(this.myPublicProperty);\n        }\n    };\n\n}();\n\n{% endhighlight %}\n\n\n**jQuery** \n\nСуществует множество способов, чтобы представить jQuery-код в виде паттерна «модуль», \nдаже если этот код не напоминает привычные jQuery-плагины. Бен Черри ранее \nпредлагал способ, при котором, если у модулей есть общие черты, то они объявляются \nчерез функцию-обертку.\n\nВ следующем примере функция `library` используется для объявления новой\nбиблиотеки и автоматически при создании библиотеки (т.е. модуля),\nсвязывает вызов метода `init` с `document.ready`.\n\n{% highlight javascript %}\n\nfunction library(module) {\n  $(function() {\n    if (module.init) {\n      module.init();\n    }\n  });\n  return module;\n}\n\nvar myLibrary = library(function() {\n   return {\n     init: function() {\n       /* код модуля */\n     }\n   };\n}());\n\n{% endhighlight %}\n\n{:class=\"message\"}\n**Ссылки по теме:**  \n[Бен Черри — Погружение в паттерн «Модуль»][5]  \n[Джон Ханн — Будущее — это модули, а не фреймворки][6]  \n[Натан Смит — Ссылки на window и document в модулях (gist)][7]  \n\n\n[3]: http://benalman.com/news/2010/11/immediately-invoked-function-expression/\n[4]: http://groups.google.com/group/comp.lang.javascript/msg/9f58bd11bd67d937\n[5]: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth\n[6]: http://lanyrd.com/2011/jsconf/sfgdk/\n[7]: https://gist.github.com/274388\n\n"
  },
  {
    "path": "_includes/translation/rus/07_object-literal-notation.md",
    "content": "<!-- ##### Литеральная нотация объекта -->\n\nВ литеральной нотации объект описывается внутри блока фигурных скобок (`{}`), \nкак набор разделенных запятой пар ключ/значение. Ключи объекта могут\nбыть как строками, так и идентификаторами. После имени ставится двоеточие.\nВ объекте не должно стоять запятой после последней пары ключ/значение,\nтак как это может привести к ошибкам.\n\nЛитерал объекта не требует использования оператора `new` для создания экземпляра,\nно он не должен стоять в начале выражения, так как открытая `{` может быть\nвоспринята как начало блока. Ниже вы можете увидеть пример модуля, определенного\nс помощью литеральной нотации объекта. Новые члены объекта могут быть добавлены\nс помощью конструкции `myModule.property = 'someValue';`\n\n{:.message}\nПаттерн «модуль» может быть полезен для многих вещей. Но если вы считаете, что вам\nне нужно делать приватными некоторые методы или свойства, то литерал объекта — \nболее чем подходящий выбор.\n\n{% highlight javascript %}\nvar myModule = {\n    myProperty: 'someValue',\n    // Литералы объектов могут содержать свойства и методы.\n    // ниже в свойстве определен другой объект,\n    // для описания конфигурации:\n    myConfig: {\n        useCaching: true,\n        language: 'en'\n    },\n    // Очень простой метод\n    myMethod: function() {\n        console.log('I can haz functionality?');\n    },\n    // вывод значения заданного в конфигурации\n    myMethod2: function() {\n        console.log('Caching is: ' + ((this.myConfig.useCaching) ? 'enabled' : 'disabled'));\n    },\n    // переопределение конфигурации\n    myMethod3: function(newConfig) {\n        if (typeof newConfig == 'object') {\n            this.myConfig = newConfig;\n            console.log(this.myConfig.language); \n        }\n    }\n};\n\nmyModule.myMethod();  // 'I can haz functionality'\nmyModule.myMethod2(); // Вывод 'enabled'\nmyModule.myMethod3({language:'fr',useCaching:false}); // 'fr'\n{% endhighlight %}\n\n{:class=\"message\"}\n**Ссылки по теме:**  \n[Ребекка Мёрфи — Использование объектов для организации вашего кода][1]  \n[Стоян Стефанов — 3 способа определения класса в JavaScript ][2]  \n[Бен Алман — Разъяснения по литералам объектов (понятия JSON-объект не существует)][3]  \n[Джон Резиг - Простое наследование в JavaScript][4]\n\n[1]: http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code\n[2]: http://www.phpied.com/3-ways-to-define-a-javascript-class/\n[3]: http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/\n[4]: http://ejohn.org/blog/simple-javascript-inheritance/\n"
  },
  {
    "path": "_includes/translation/rus/08_commonjs-modules.md",
    "content": "<!-- ### CommonJS Модули -->\n\n\nВозможно, вы что-то слышали о [CommonJS][4] за последние пару лет. CommonJS — это\nдобровольная рабочая группа, которая проектирует, прототипирует и стандартизирует\nразличные JavaScript API. На сегодняшний день они ратифицировали стандарты для\nмодулей и пакетов — CommonJS определяют простой API для написания модулей,\nкоторые могут быть использованы в браузере с помощью тега `<script>`, как \nс синхронной, так и с асинхронной загрузкой. Реализация паттерна «модуль»\nс помощью CommonJS выглядит очень просто, и я нахожу это уверенным шагом на пути\nк модульной системе, предложенной в ES Harmony (следующей версии JavaScript).\n\nВ структурном плане, CommonJS-модуль представляет собой готовый к переиспользованию\nфрагмент JavaScript-кода, который экспортирует специальные объекты, доступные\nдля использования в любом зависимом коде. CommonJS все чаще используется как\nстандартный формат JavaScript-модулей. Существует большое количество хороших\nуроков по написанию CommonJS-модулей, но обычно они описывают две главных идеи: \nобъект `exports`, содержащий то, что модуль хочет сделать доступным для других\nчастей системы, и функцию `require`, которая используется одними модулями для\nимпорта объекта `exports` из других.\n\n{% highlight javascript %}\n/*\nПример обеспечения совместимости между AMD и обычным CommonJS с помощью\nсоздания обертки над последним:\n*/\n\n(function(define) {\ndefine(function(require,exports) {\n  // module contents\n  var dep1 = require(\"dep1\");\n  exports.someExportedFunction = function() {...};\n  //...\n});\n})(typeof define==\"function\"?define:function(factory){factory(require,exports)});\n{% endhighlight %}\n\nЕсть много хороших JavaScript-библиотек, для загрузки модулей в формате\n**CommonJS**, но моим личным предпочтением является RequireJS. Полный учебник\nпо RequireJS выходит за рамки этого руководства, но я могу порекомендовать вам\nпочитать [пост Джеймса Брука «ScriptJunkie»][5]. Кроме того, я знаю многих людей,\nкоторые предпочитают Yabble.\n\nИз коробки, RequireJS уже содержит методы для простого создания статичных\nмодулей с обертками. Благодаря этим методам становится действительно легко\nсоздавать модули с поддержкой асинхронной загрузки. RequireJS может легко\nзагружать модули и их зависимости, выполняя тело модуля, сразу, как только это\nстановится возможным.\n\nНекоторые разработчики утверждают, что CommonJS-модули недостаточно удобны\nдля применения в браузере, потому как без определенной помощи со стороны сервера,\nих нельзя загрузить с помощью тега `script`. Давайте представим, что есть некая\nбиблиотека для кодирования изображений в виде ASCII-изображений, которая\nэкспортирует функцию `encodeToASCII`. Модуль использующий эту библиотеку\nбудет выглядеть примерно так:\n\n{% highlight javascript %}\nvar encodeToASCII = require(\"encoder\").encodeToASCII;\nexports.encodeSomeSource = function() {\n  // Обработка изображения, затем вызов encodeToASCII\n}\n{% endhighlight %}\n\nЭтот код не будет работать с тегом `script`. Ему необходим определенный контекст.\nЯ имею в виду наш метод `encodeToASCII`, который ссылается на несуществующие\nв контексте `window` методы `require` и `exports`. В такой ситуации нам пришлось\nбы писать `require` и `exports` для каждого отдельного модуля. Эту проблему\nлегко решают клиентские библиотеки, которые загружают скрипты через XHR-запросы,\nа затем выполняют `eval()`.\n\nПопробуем переписать этот модуль, используя RequireJS:\n\n{% highlight javascript %}\ndefine(function(require, exports, module) {\n  var encodeToASCII = require(\"encoder\").encodeToASCII;\n  exports.encodeSomeSource = function() {\n    // Обработка изображения, затем вызов encodeToASCII\n  }\n});\n{% endhighlight %}\n\nДля разработчиков, которые хотят пойти дальше простого использования JavaScript\nв своих проектах, CommonJS модули — прекрасная возможность начать движение в эту\nсторону, но придется потратить немного времени и познакомиться поближе с этим\nформатом. Все, что я рассказал — это только верхушка айсберга. К счастью, \nCommonJS wiki и SitePen содержат много материалов, которые помогут вам глубже\nразобраться в устройстве CommonJS-модулей.\n\n{:class=\"message\"}\n**Ссылки по теме:**  \n[Спецификации CommonJS-модулей][1]  \n[Алекс Янг - Прояснение CommonJS-модулей][2]  \n[Заметки о CommonJS- и RequireJS-модулях][3]  \n\n[1]: http://wiki.commonjs.org/wiki/Modules\n[2]: http://dailyjs.com/2010/10/18/modules/\n[3]: http://requirejs.org/docs/commonjs.html#packages\n[4]: http://commonjs.org\n[5]: http://msdn.microsoft.com/en-us/scriptjunkie/ff943568\n"
  },
  {
    "path": "_includes/translation/rus/09_the-facade-pattern.md",
    "content": "<!-- ### Паттерн «Фасад» -->\n\nКлючевую роль в архитектуре, которую мы обсуждаем в этой книге, играет\nшаблон проектирования под названием «фасад».\n\nКак правило, фасад используется для создания некоторой абстракции,\nскрывающей за собой совершенно иную реальность. Паттерн «фасад»\nобеспечивает удобный **высокоуровневый интерфейс** для больших блоков\nкода, скрывая за собой их истинную сложность. Относитесь к фасаду, как\nк упрощенному API, который вы отдаете в пользование другим разработчикам.\n\nФасад — **структурный паттерн**. Часто его можно обнаружить\nв JavaScript-библиотеках и фреймворках, где пользователям доступен\nтолько фасад — ограниченная абстракция широкого диапазона поведений\nреализованных внутри.\n\nБлагодаря такому подходу, пользователь взаимодействует только с интерфейсом, \nне имея никакого представления о подсистемах, которые скрываются за ним.\n\nПричина, по которой нам интересен фасад — возможность скрыть детали реализации \nконкретной функциональности, хранящиеся в модулях. Это позволит нам вносить изменения\nв реализацию, не сообщая об этом пользователям.\n\nНадежный фасад — наш упрощенный интерфейс — позволит нам не беспокоиться о тесных\nсвязях некоторых модулей нашей системы с dojo, jQuery, YUI, zepto или какой-либо\nдругой библиотекой. Это становится не так важно. Вы можете переходить с одной\nбиблиотеки на другую не меняя слой взаимодействия. К примеру, с jQuery на dojo.\nБолее того, у вас появляется возможность совершить такой переход на более поздних\nэтапах, без изменений в остальных частях системы.\n\nНиже я написал достаточно простой пример использования фасада. Как вы видите,\nу нашего модуля есть несколько приватных методов. Чтобы создать более простой\nинтерфейс для доступа к этим методам мы используем фасад.\n\n{% highlight javascript %}\nvar module = (function() {\n  var _private = {\n    i: 5,\n    get: function() {\n      console.log('Текущее значение:' + this.i);\n    },\n    set: function(val) {\n      this.i = val;\n    },\n    run: function() {\n      console.log('процесс запущен');\n    },\n    jump: function() {\n      console.log('резкое изменение');\n    }\n  };\n  return {\n    facade: function(args) {\n      _private.set(args.val);\n      _private.get();\n      if (args.run) {\n        _private.run();\n      }\n    }\n  }\n}());\n\nmodule.facade({run:true, val:10}); // Текущее значение: 10, процесс запущен\n{% endhighlight %}\n\n\nЭто и есть та причина, по которой мы добавили фасад к нашей архитектуре.\nВ следующей главе мы обсудим медиатор. Принципиальное различие между\nэтими двумя паттернами заключается в том, что фасад, как структурный паттерн,\nвсего лишь передает существующую функциональность в медиатор, в то время как\nмедиатор, как поведенческий паттерн, может эту функциональность расширять.\n\n{:class=\"message\"}\n**Ссылки по теме:**  \n[Дастин Диас, Росс Хармс — «Профессиональные шаблоны проектирования JavaScript» (Глава 10, доступно для чтения в Google Books)][1]  \n\n[1]: http://books.google.co.uk/books?id=za3vlnlWxb0C&lpg=PA141&ots=MD5BLTsSzH&dq=javascript%20facade%20pattern&pg=PA141#v=onepage&q=javascript facade pattern&f=false\n"
  },
  {
    "path": "_includes/translation/rus/10_the-mediator-pattern.md",
    "content": "<!-- ### Паттерн «Медиатор» -->\n\nОбъяснить, что представляет собой паттерн «медиатор» достаточно просто на примере\nследующей аналогии — представьте себе контроль трафика в аэропорту: все решения\nо том, какие самолеты могут взлетать или садиться, принимает диспетчер. Для этого,\nвсе сообщения, исходящие от самолетов, поступают в башню управления, вместо того,\nчтобы пересылаться между самолетами напрямую. Такой централизованный контроллер —\nэто и есть ключ к успеху нашей системы. Это и есть «медиатор».\n\n{:.message}\nМедиатор применяется в системах, где взаимодействие между модулями может быть\nвесьма сложными, но, в то же время, **хорошо определенными**. Если вы полагаете,\nчто связи между модулями вашей системы будут постоянно расти и усложняться, то, \nвозможно, вам стоит добавить центральный элемент управления. Паттерн «медиатор»\nотлично подходит для этой роли.\n\nМедиатор выступает в качестве посредника в общении между различными модулями,\n**инкапсулируя их взаимодействие**. Кроме того, этот шаблон проектирования,\nпредотвращая прямое взаимодействие различных компонентов системы, способствует\nослаблению связей в коде. В нашей системе он также помогает в решении проблем,\nсвязанных с зависимостями модулей.\n\nКакие еще преимущества существуют у «медиатора»? К примеру, медиатор позволяет\nкаждому модулю функционировать абсолютно независимо от других компонентов системы,\nчто приводит к большей гибкости. Если вам ранее уже приходилось использовать\nпаттерн «наблюдатель» в роли системы доставки событий между различными частями\nв вашей системе, то вам не составит труда разобраться с медиатором.\n\nДавайте посмотрим на модель взаимодействия модулей и медиатора:\n\n![][7]\n\nМы можем рассматривать модули, как «издателей», публикующих события. Медиатор же\nявляется и «издателем» и «подписчиком» одновременно. В примере, `Module 1` посылает\nсообщение, предполагающее некоторую реакцию, медиатору. Затем, медиатор, получив\nсообщение, уведомляет другие модули об определенных действиях, которые необходимо\nвыполнить для завершения задачи. `Module 2` выполняет необходимые `Module 1`\nдействия, и сообщает о результате обратно, в медиатор. В это же время, медиатор\nзапускает `Module 3` для логгирования поступающих сообщений.\n\nОбратите внимание: здесь нет прямого взаимодействия между модулями. Если\nв `Module 3` произойдет ошибка или, к примеру, он просто перестанет работать,\nто медиатор, теоретически, может приостановить выполнение задач в других модулях,\nзатем перезапустить `Module 3` и продолжить работу, практически не влияя на работу\nвсей системы. Такая слабая связанность модулей является одним из самых сильных\nпреимуществ паттерна «медиатор», который я вам предлагаю использовать.\n\nПосмотрим на его преимущества:\n\nУменьшает связывание модулей, добавляя посредника — центральный элемент управления.\nЭто позволяет модулям отправлять и слушать сообщения, не затрагивая остальной\nчасти системы. Сообщения могут быть обработаны любым количеством модулей сразу.\n\n\nБлагодаря слабой связанности кода, внедрение новой функциональности \nпроисходит существенно легче.\n\n\nИ недостатки:\n\nМодули больше не могут взаимодействовать напрямую. Использование медиатора\nприводит к небольшому падению производительности — такова природа слабой\nсвязанности — становится достаточно трудно определить реакцию системы,\nотталкиваясь только от событий, происходящих в ней. \n\nНаконец, системы с высокой связанностью кода являются обычно источником\nвсевозможных проблем, решением которых может стать уменьшение связанности.\n\n\n**Пример:** одна из возможных реализаций паттерна «медиатор», основанная на работе\n[@rpflorence][8]\n\n{% highlight javascript %}\nvar mediator = (function() {\n    var subscribe = function(channel, fn) {\n        if (!mediator.channels[channel]) mediator.channels[channel] = [];\n        mediator.channels[channel].push({ context: this, callback: fn });\n        return this;\n    },\n \n    publish = function(channel) {\n        if (!mediator.channels[channel]) return false;\n        var args = Array.prototype.slice.call(arguments, 1);\n        for (var i = 0, l = mediator.channels[channel].length; i < l; i++) {\n            var subscription = mediator.channels[channel][i];\n            subscription.callback.apply(subscription.context, args);\n        }\n        return this;\n    };\n \n    return {\n        channels: {},\n        publish: publish,\n        subscribe: subscribe,\n        installTo: function(obj) {\n            obj.subscribe = subscribe;\n            obj.publish = publish;\n        }\n    };\n\n}());\n{% endhighlight %}\n\n\nИ два примера использования реализации, написанной выше:\n\n{% highlight javascript %}\n//Pub/sub on a centralized mediator\n\nmediator.name = \"tim\";\nmediator.subscribe('nameChange', function(arg) {\n    console.log(this.name);\n    this.name = arg;\n    console.log(this.name);\n});\n\nmediator.publish('nameChange', 'david'); //tim, david\n\n\n//Pub/sub via third party mediator\n\nvar obj = {name: 'sam'};\nmediator.installTo(obj);\nobj.subscribe('nameChange', function(arg) {\n    console.log(this.name);\n    this.name = arg;\n    console.log(this.name);\n});\n\nobj.publish('nameChange', 'john'); //sam, john\n{% endhighlight %}\n\n{:class=\"message\"}\n**Ссылки по теме:**  \nStoyan Stefanov — Page 168, JavaScript Patterns  \n[HB Stone — Шаблоны проектирования JavaScript: Медиатор][1]  \n[NVince Huston — Шаблон Медиатора (не относится JavaScript, но кратко)][2]  \n\n\n[1]: http://arguments.callee.info/2009/05/18/javascript-design-patterns--mediator/\n[2]: http://www.vincehuston.org/dp/mediator.html\n\n[7]: /assets/img/chart4a.jpg\n[8]: https://github.com/rpflorence\n"
  },
  {
    "path": "_includes/translation/rus/11_applying-the-facade-abstraction-of-the-core.md",
    "content": "<!-- ### Использование фасада: абстракция ядра -->\n\n{:.message}\nФасад, в нашей архитектуре, выполняет роль **абстракции** ядра приложения. Фасад\nнаходится между медиатором и модулями. Модули в идеальной ситуации должны\nвзаимодействовать **исключительно** с фасадом и не должны знать абсолютно ничего\nо других компонентах нашей системы.\n\nФасад также обеспечивает **последовательный и доступный в любой момент интерфейс**\nдля модулей. Это похоже на **песочницу** в архитектуре Николаса Закаса.\n\nВсе сообщения от модулей, адресованные медиатору, проходят через фасад, поэтому\nон должен быть весьма надежен. Его роль в этом взаимодействии — анализ\nсообщений, исходящих от модулей, и передача этих сообщений в медиатор.\n\nВ дополнение к предоставлению интерфейса, фасад также выступает в роли защиты,\nопределяя с какими частями системы может взаимодейстовать модуль. Модули\nмогут вызывать только **свои собственные** методы. Для доступа к другим\nкомпонентам системы модулям необходимо иметь специальное разрешение.\n\nК примеру, модуль может отправить сообщение `dataValidationCompletedWriteToDB`.\nВ подобных случаях задача фасада — убедиться, действительно ли этот модуль\nимеет права на запись в базу данных. Таким образом, мы пытаемся предотвратить\nпроблемы с модулями, которые пытаются делать то, что они не должны. \n\nПодведем итоги: медиатор представляет собой интерпретацию паттерна «подписчик/издатель», \nно он получает только те сообщения, которые нас действительно интересуют. За\nфильтрацию же всех сообщений отвечает фасад.\n"
  },
  {
    "path": "_includes/translation/rus/12_applying-the-mediator-the-application-core.md",
    "content": "<!-- ### Использование медиатора: ядро приложения -->\n\nВ этой главе мы кратко пройдемся по некоторым зонам ответственности\nмедиатора, который играет роль ядра приложения. Но для начала\nдавайте разберемся, что он представляет собой в целом. \n\nОсновная задача ядра — управлять **жизненным циклом** модулей. Когда ядро \nполучает **интересное сообщение** от модулей, оно должно определить, как\nприложение должно на это отреагировать, таким образом ядро определяет момент\n**запуска** или **остановки** определенного модуля или набора модулей.\n\n{:.message}\nВ идеальной ситуации, однажды запущенный модуль, должен функционировать\nсамостоятельно. В задачи ядра не входит принятие решений о том, как реагировать,\nнапример, на событие `DOM ready` — в нашей архитектуре у модулей есть достаточно\nвозможностей для того, чтобы принимать такие решения самостоятельно.\n\nВозможно, у вас вызовет удивление то обстоятельство, что модулям может\nпотребоваться остановка. Такое может произойти в случае, если модуль вышел из строя,\nлибо если в работе модуля происходят серьезные ошибки. Решение об остановке\nмодуля может помочь предотвратить некорректную работу его методов.\nПоследующий перезапуск таких модулей должен помочь решить возникшие проблемы.\nЦель здесь в минимизации негативных последствий для пользователя нашего приложения.\n\nВ дополнение, ядро должно быть в состоянии **добавлять или удалять** модули\nне ломая ничего. Типичный пример — определенный набор функций может быть\nнедоступен на начальном этапе загрузки страницы, но эти функции могут быть\nзагружены динамически, на основе определенных действий со стороны пользователя.\nВозвращаясь к нашему примеру с GMail, Google может по умолчанию держать чат\nв свернутом состоянии и загружать соответствующий ему модуль динамически,\nтолько в том случае, если пользователь проявит интерес к использованию этой\nчасти приложения. С точки зрения оптимизации производительности, это должно\nдать заметный эффект.\n\nОбслуживание ошибок должно также обрабатываться ядром приложения. В добавок\nк сообщению об интересных событиях модули также должны сообщать и о любых ошибках\nкоторые произошли в их работе. Ядро должно соответствующим образом реагировать\nна эти ошибки (к примеру, останавливать модули, перезапускать их и т.д.). Это\nважно, как часть слабо связанной архитектуры, позволяющей реализовать новый\nили лучший подход к реализации уведомления пользователя об ошибках без ручного\nизменения в каждом модуле. Используя механизм для публикации событий и подписки\nна них в медиаторе мы сможем достичь этого.\n"
  },
  {
    "path": "_includes/translation/rus/13_tying-it-all-together.md",
    "content": "<!-- ### Собираем всех вместе -->\n\n*   **Модули** содержат специфичные части функциональности вашего приложения.\n    Они публикуют уведомления, информирующие приложение о том, что случилось\n    что-то интересное. Это их главная забота. Как я поясню в FAQ, модули\n    могут зависеть от различных вспомогательных методов для работы с DOM, но\n    идеальным бы было отсутствие любых зависимостей от других компонентов\n    системы. Модули не должны иметь отношение к тому:\n\n    *   какие объекты или модули подписаны на их сообщения,\n    *   где находятся эти объекты (на клиенте или на сервере),\n    *   какое количество объектов подписано на уведомления.\n\n**![][9]**\n\n*   **Фасад** — абстракция ядра защищающая его от прямого контакта\n    с модулями. Он подписывается на интересные сообщения от модулей, и говорит:\n    «Отлично! Что случилось? Расскажи мне больше подробностей!». Так же фасад\n    поддерживает безопасность модулей, проверяя, действительно ли модуль,\n    отправивший сообщение, имеет необходимые права для того, чтобы его сообщение\n    было соответствующим образом обработано ядром.\n\n**![][10]**\n\n*   **Медиатор (ядро приложения)** выступает в роли управляющего публикациями\n    событий и подписками на них. Он отвечает за управление запуском и остановку\n    модулей по необходимости. Здесь используется частичная динамическая загрузка\n    зависимостей, и гарантия того, что упавшие модули могут быть централизованно\n    перезапущены в случае проблем.\n\n**![][11]**\n\nИтог этой архитектуры в том, что модули, в большинстве случаев, практически \nне зависят от других компонентов приложения. Они могут быть легко тестируемы\nи легко поддерживаемы в рамках своего кода. Кроме того, благодаря низкому уровню\nсвязанности кода, такие модули можно легко скопировать на новую страницу для\nиспользования в другом проекте, не прилагая дополнительных усилий. Так же, эти\nмодули могут быть загружены или удалены динамически в процессе работы приложения.\n\n\n[9]: /assets/img/chart1a.gif\n[10]: /assets/img/chart2a.gif\n[11]: /assets/img/chart3a.gif\n"
  },
  {
    "path": "_includes/translation/rus/14_beyond-pub-sub-automatic-event-registration.md",
    "content": "<!-- ### Развитие идей медиатора: автоматическая регистрация событий -->\n\nКак раньше упоминал Михаэль Махемофф, размышляя о больших и масштабируемых \nJavaScript-приложениях, весьма выгодно использовать в приложении больше динамических\nсвойств языка. Вы можете прочитать об этом больше в его заметках на странице\n[Google+][12], но я хочу подробнее остановиться на одной особенности —\nавтоматической регистрации событий (AER).\n\nAER решает проблему связывания подписчиков и издателей путем добавления паттерна,\nкоторый автоматически вызывает нужные методы на основе соглашения об именовании.\nНапример, если модуль публикует сообщение `messageUpdate`, произойдет\nавтоматический вызов одноименного метода у всех модулей, которые такой имеют.\n\nИспользование этого паттерна подразумевает регистрацию всех компонентов,\nкоторые могут подписываться на события, регистрацию всех событий на которые\nможно подписаться и, наконец, для каждого метода подписки в вашем наборе\nкомпонентов должно быть событие. Это выглядит очень интересно по отношению\nк нашей архитектуре, но так же имеет ряд интересных проблем.\n\nК примеру, при работе динамически, объекты должны регистрировать себя после\nсоздания. Если вас это заинтересовало — посмотрите [пост][13] Михаэля об AER,\nгде он более подробно обсуждает как бороться с проблемами этого подхода.\n\n[12]: https://plus.google.com/106413090159067280619/posts/hDZkVrDXZR6\n[13]: http://softwareas.com/automagic-event-registration\n"
  },
  {
    "path": "_includes/translation/rus/15_frequently-asked-questions.md",
    "content": "<!-- ### Frequently Asked Questions -->\n\n### Возможно ли обойтись без использования фасада (песочницы)?\n\nХотя архитектура, которую я изложил здесь, использует фасад для обеспечения\nбезопасности, вполне возможно достичь того же с помощью медиатора — сообщения\nмогут обрабатываться непосредственно ядром без использования фасада. Такая\nупрощенная версия все равно будет обеспечивать необходимо низкий уровень\nсвязывания кода, но при выборе этого варианта, нужно понимать, насколько вам\nбудет комфортно работать с модулями, которые взаимодействуют напрямую\nс ядром.\n\n### В книге говорилось о том, что модули не должны иметь любых зависимостей, касается ли это библиотек (к примеру, jQuery)?\n\nЯ специально вынес вопрос о зависимостях от других модулей сюда. Когда\nнекоторые разработчики выбирают подобную архитектуру, этот выбор подразумевает\nчто они будут использовать определенные абстракции от DOM-библиотек. К примеру,\nвы можете использовать вспомогательную утилиту, которая будет возвращать нужные\nвам DOM-элементы используя jQuery (или dojo). Благодаря этому, модули все еще могут\nудобно работать с DOM, но уже будут это делать не напрямую, жестко используя\nконкретную библиотеку. Существует достаточно много способов, как сделать\nмодули независимыми, но стоит понимать, что, в обсуждаемой нами архитектуре,\nидеальные модули не должны иметь зависимостей.\n\nВы заметите, что иногда при таком подходе становится гораздо легче взять\nзаконченный модуль из одного проекта и перенести его в другой проект с небольшими\nдополнительными усилиями. Должен сказать, я полностью согласен с тем, что\nпорой намного лучше, когда модули, вместо определенной части своей функциональности,\nпросто используют другие модули. Как бы то ни было, держите в голове то, что\nтакие модули, в некоторых случаях, могут потребовать гораздо больше усилий для\nпереноса в другой проект.\n\n### Я хочу сегодня же начать использовать эту архитектуру. Есть ли какой-то шаблон от которого я бы мог оттолкнуться?\n\nКогда у меня будет немного свободного времени, я планирую написать для этой\nкниги бесплатный шаблон проекта, но сейчас, наверное, лучший выбор — \nплатное учебное пособие написанное Эндрю Бэджис — [«Написание модульного JavaScript»][14]\n(разоблачу себя: деньги от этой реферальной ссылки, как и любые другие, полученные\nот этой книги деньги уже инвестируются в обзор будущих материалов перед тем, как я порекомендую их другим).\nПособие Эндрю включает в себя скринкаст и примеры кода. Оно охватывает большую\nчасть идей, которые мы обсуждали в книге, но в нем, вместо названия «фасад» \nиспользуется слово «песочница», как у Николаса Закаса. Так же, здесь есть\nобсуждение о том, что работа с DOM-библиотеками, в идеале, должна быть реализована\nпосредством абстракции. Я говорил об этом в предыдущем вопросе. Тут Эндрю\nделает ставку на некоторые интересные шаблоны, обобщающие работу с селекторами\nDOM, таким образом, в крайнем случае, замена библиотеки может быть выполнена\nв несколько коротких строк. Я не говорю, что это лучший или самый правильный\nподход, но я поступаю именно так.\n\n### Могут ли модули взаимодействовать с ядром напрямую, если это необходимо?\n\nКак заметил раньше Николас Закас, технически, нет никаких причин, мешающих\nмодулям напрямую обращаться к ядру. Это скорее относится к «лучшим практикам».\nЕсли вы намерены строго следовать этой архитектуре, то вы должны также следовать\nее правилам. Либо следовать правилам более простой архитектуры, которая была\nописана в первом вопросе.\n\n\n[14]: http://bit.ly/orGVOL\n"
  },
  {
    "path": "_includes/translation/rus/16_credits.md",
    "content": "<!-- ### Credits -->\n\nСпасибо Николасу Закасу за его оригинальную работу в объединении большого\nколичества концепций существующих на сегодняшний день. Спасибо Андрэ Хэнссон\nза технический обзор книги и за отзывы, которые помогли сделать эту книгу лучше.\nСпасибо Ребекке Мюрфей, Джастину Майеру, Питеру Мишо, Полу Айришу и Алексу\nСекстону и всем, чьи материалы относятся к теме обсуждаемой в книге и являлись\nисточником вдохновения как для меня так и для других.\n"
  },
  {
    "path": "_includes/translation/rus/readme.md",
    "content": "{:class=\"intro\"}\n<!-- **От переводчиков**  \nМы еще работаем над переводом этой книги но, чтобы не оттягивать удовольствие\nпознакомиться с этой потрясающей работой, мы решили опубликовать первые главы, а\nзатем, регулярно выкладывать новые. Следите за проектом в [Twitter][2] или с помощью\n[RSS][3].\n -->\nВ этой книге мы обсудим набор паттернов, который поможет вам в создании \nбольших масштабируемых JavaScript-приложений. Материал книги основан на моем\nодноименном докладе, впервые прочитанном на конференции «LondonJS», и\nвдохновленном [предшествующей ему работой][1] Николаса Закаса.\n\nВы можете скачать эту книгу в форматах: [epub][4], [mobi][5], [fb2][6] и [pdf][7].\n\n[1]: http://www.slideshare.net/nzakas/scalable-javascript-application-architecture\n[2]: https://twitter.com/largescaleJS_ru\n[3]: /atom.xml\n\n[4]: /epub/largescale-js.epub\n[5]: /epub/largescale-js.mobi\n[6]: /epub/largescale-js.fb2\n[7]: /epub/largescale-js.pdf\n"
  },
  {
    "path": "_layouts/page.html",
    "content": "<!doctype html>\n<html lang=\"ru\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"google-site-verification\" content=\"CWc2hik7IPJSBgC9Ci7-mYAIW69Hn4dyqxkeYuM6ht4\" />\n  <meta name='yandex-verification' content='741dfa8d176f107e' />\n  {% if page.index == true %}\n    <title>«{{ site.title }}» от {{ site.author }}</title>\n  {% else %}\n    <title>{{ page.title }} — «{{ site.title }}»</title>\n  {% endif %}\n  <link rel=\"stylesheet\" href=\"/assets/css/main.css\">\n  <link rel=\"stylesheet\" href=\"/assets/css/pygments.css\">\n  <link rel=\"stylesheet\" href=\"/assets/vendor/social-likes/social-likes.css\">\n  <link rel=\"stylesheet\" href=\"/assets/css/print.css\" media=\"print\">\n</head>\n<body>\n  {% include fork-me.html %}\n  <div class=\"wrapper\">\n    {% include page-header.html %}\n    {% include lazada-banner.html %}\n    {% include social-likes.html %}\n    <div class=\"content\">\n      {{ content }}\n      {% include prevnext.html %}\n    </div>\n    <div class=\"footer\">\n      {% if page.index == true %}\n        {% include money.html %}\n      {% else %}\n        {% include disqus.html %}\n      {% endif %}\n      <p>\n        {% include prose.html %}\n        <br>\n        Перевод:\n          <a class=\"ignore-visited\" href='http://shuvalov.info'>Антон Шувалов</a>.   \n        Помощь в переводе:\n          <a class=\"ignore-visited\" href='http://twitter.com/iamstarkov'>Владимир Старков</a>, \n          <a class=\"ignore-visited\" href='http://freetonik.com/'>Рахим Давлеткалиев</a>.\n        <br/>\n          <a class=\"ignore-visited\" href='https://github.com/shuvalov-anton/largescaleJS_ru/graphs/contributors'>Все участники</a>.\n      </p>\n        {% include license.html %}\n    </div>\n  </div>\n  <script src=\"/assets/vendor/jquery/jquery-2.0.3.min.js\"></script>\n  <script src=\"/assets/vendor/social-likes/social-likes.min.js\"></script>\n  {% include analytics.html %}\n</body>\n</html>\n"
  },
  {
    "path": "_posts/04-02-2014-the-mediator-pattern.md",
    "content": "---\nlayout: page\ntitle: \"Глава 10. Паттерн «Медиатор»\"\npath: translation/rus/10_the-mediator-pattern.md\npublished: true\n---\n\n{% include translation/rus/10_the-mediator-pattern.md %}\n"
  },
  {
    "path": "_posts/07-02-2014-applying-the-facade-abstraction-of-the-core.md",
    "content": "---\n\nlayout: page\ntitle: \"Глава 11. Использование фасада: абстракция ядра\"\npath: translation/rus/11_applying-the-facade-abstraction-of-the-core.md\npublished: true\n\n---\n\n{% include translation/rus/11_applying-the-facade-abstraction-of-the-core.md %}"
  },
  {
    "path": "_posts/09-01-2014-intro.md",
    "content": "---\nlayout: page\ntitle: \"Введение\"\npath: translation/rus/00_intro.md\npublished: true\n---\n\n{% include translation/rus/00_intro.md %}\n"
  },
  {
    "path": "_posts/10-01-2014-what-exactly-is-a-large-javascript-application.md",
    "content": "---\nlayout: page\ntitle: \"Глава 1. Что представляет собой «большое» JavaScript-приложение?\"\npath: translation/rus/01_what-exactly-is-a-large-javascript-application.md\npublished: true\n---\n\n{% include translation/rus/01_what-exactly-is-a-large-javascript-application.md %}\n"
  },
  {
    "path": "_posts/11-01-2014-lets-review-your-current-architecture.md",
    "content": "---\nlayout: page\ntitle: \"Глава 2. Давайте обсудим вашу существующую архитектуру\"\npath: translation/rus/02_lets-review-your-current-architecture.md\npublished: true\n---\n\n{% include translation/rus/02_lets-review-your-current-architecture.md %}\n"
  },
  {
    "path": "_posts/11-02-2014-applying-the-mediator-the-application-core.md",
    "content": "---\nlayout: page\ntitle: \"Глава 12. Использование медиатора: ядро приложения\"\npath: translation/rus/12_applying-the-mediator-the-application-core.md\npublished: true\n---\n\n{% include translation/rus/12_applying-the-mediator-the-application-core.md %}\n"
  },
  {
    "path": "_posts/14-02-2014-tying-it-all-together.md",
    "content": "---\nlayout: page\ntitle: \"Глава 13. Собираем все вместе\"\npath: translation/rus/13_tying-it-all-together.md\npublished: true\n---\n\n{% include translation/rus/13_tying-it-all-together.md %}\n"
  },
  {
    "path": "_posts/15-01-2014-think-long-term.md",
    "content": "---\nlayout: page\ntitle: \"Глава 3. Думай о будущем\"\npath: translation/rus/03_think-long-term.md\npublished: true\n---\n\n{% include translation/rus/03_think-long-term.md %}\n"
  },
  {
    "path": "_posts/16-01-2014-brainstorm.md",
    "content": "---\nlayout: page\ntitle: \"Глава 4. Мозговой штурм\"\npath: translation/rus/04_brainstorming.md\npublished: true\n---\n\n{% include translation/rus/04_brainstorming.md %}\n"
  },
  {
    "path": "_posts/17-01-2014-module-theory.md",
    "content": "---\nlayout: page\ntitle: \"Глава 5. Теория модулей\"\npath: translation/rus/05_module-theory.md\npublished: true\n---\n\n{% include translation/rus/05_module-theory.md %}\n"
  },
  {
    "path": "_posts/18-02-2014-beyond-pub-sub-automatic-event-registration.md",
    "content": "---\nlayout: page\ntitle: \"Глава 14. Развитие идеи медиатора: автоматическая регистрация событий\"\npath: translation/rus/14_beyond-pub-sub-automatic-event-registration.md\npublished: true\n---\n\n{% include translation/rus/14_beyond-pub-sub-automatic-event-registration.md %}\n"
  },
  {
    "path": "_posts/19-02-2014-faq.md",
    "content": "---\nlayout: page\ntitle: \"Часто задаваемые вопросы\"\npath: translation/rus/15_frequently-asked-questions.md\npublished: true\n---\n\n{% include translation/rus/15_frequently-asked-questions.md %}\n"
  },
  {
    "path": "_posts/20-02-2014-credits.md",
    "content": "---\nlayout: page\ntitle: \"Благодарности\"\npath: translation/rus/16_credits.md\npublished: true\n---\n\n{% include translation/rus/16_credits.md %}\n"
  },
  {
    "path": "_posts/21-01-2014-module-pattern.md",
    "content": "---\nlayout: page\ntitle: \"Глава 6. Паттерн «Модуль»\"\npath: translation/rus/06_the-module-pattern.md\npublished: true\n---\n\n{% include translation/rus/06_the-module-pattern.md %}\n"
  },
  {
    "path": "_posts/24-01-2014-object-literal-notation.md",
    "content": "---\nlayout: page\ntitle: \"Глава 7. Литеральная нотация объектов\"\npath: translation/rus/07_object-literal-notation.md\npublished: true\n---\n\n{% include translation/rus/07_object-literal-notation.md %}\n"
  },
  {
    "path": "_posts/28-01-2014-commonjs-modules.md",
    "content": "---\nlayout: page\ntitle: \"Глава 8. Модули CommonJS\"\npath: translation/rus/08_commonjs-modules.md\npublished: true\n---\n\n{% include translation/rus/08_commonjs-modules.md %}\n"
  },
  {
    "path": "_posts/31-01-2014-the-facade-pattern.md",
    "content": "---\nlayout: page\ntitle: \"Глава 9. Паттерн «Фасад»\"\npath: translation/rus/09_the-facade-pattern.md\npublished: true\n---\n\n{% include translation/rus/09_the-facade-pattern.md %}\n"
  },
  {
    "path": "_stylus/_nib/Readme.md",
    "content": "[![Build Status](https://travis-ci.org/visionmedia/nib.png?branch=master)](https://travis-ci.org/visionmedia/nib)\n\n# Nib\n\n  Stylus mixins, utilities, components, and gradient image generation. Don't forget to check out the [documentation](http://visionmedia.github.com/nib/).\n\n## Installation\n\n```bash\n$ npm install nib\n```\n\n If the image generation features of Nib are desired, such as generating the linear gradient images, install [node-canvas](http://github.com/learnboost/node-canvas):\n \n```bash \n$ npm install canvas\n```\n\n## JavaScript API\n\n Below is an example of how to utilize nib and stylus with the connect framework (or express).\n\n```javascript\nvar connect = require('connect')\n  , stylus = require('stylus')\n  , nib = require('nib');\n\nvar server = connect();\n\nfunction compile(str, path) {\n  return stylus(str)\n\t.set('filename', path)\n\t.set('compress', true)\n\t.use(nib());\n}\n\nserver.use(stylus.middleware({\n\tsrc: __dirname\n  , compile: compile\n}));\n```\n\n## Stylus API\n\n  To gain access to everything nib has to offer, simply add:\n\n  ```css\n  @import 'nib'\n  ```\n  \n  Or you may also pick and choose based on the directory structure in `./lib`, for example:\n  \n  ```css\n  @import 'nib/gradients'\n  @import 'nib/overflow'\n  ```\n  \nto be continued....\n\n## More Information\n\n  - Introduction [screencast](http://www.screenr.com/M6a)\n\n## Testing\n\n You will first need to install the dependencies:\n \n ```bash\n    $ npm install -d\n ```\n \n Run the automated test cases:\n \n ```bash\n    $ npm test\n ```\n \n For visual testing run the test server:\n \n ```bash\n    $ npm run-script test-server\n ```\n \n Then visit `localhost:3000` in your browser.\n\n## Contributors\n\nI would love more contributors. And if you have helped out, you are awesome! I want to give a huge thanks to these people:\n\n  - [TJ Holowaychuk](https://github.com/visionmedia) (Original Creator)\n  - [Sean Lang](https://github.com/slang800) (Current Maintainer)\n  - [Isaac Johnston](https://github.com/superstructor)\n  - [Everyone Else](https://github.com/visionmedia/nib/contributors)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "_stylus/_nib/iconic/demo.html",
    "content": "<html>\n<head>\n<link rel=\"stylesheet\" href=\"iconic.css\" type=\"text/css\" media=\"screen\" title=\"no title\" charset=\"utf-8\">\n\n<style>\n\tbody {\n\t\tfont-size:21px;\n\t}\n</style>\n</head>\n<body>\n<ul>\t\n<li><a name='home' class='iconic home'></a> Home</li>\n<li><a name='at' class='iconic at'></a> At Symbol</li>\n<li><a name='quote' class='iconic quote'></a> Quote</li>\n<li><a name='quote-alt' class='iconic quote-alt'></a> Quote (alternate)</li>\n<li><a name='arrow-up' class='iconic arrow-up'></a> Arrow Up</li>\n<li><a name='arrow-right' class='iconic arrow-right'></a> Arrow Right</li>\n<li><a name='arrow-bottom' class='iconic arrow-bottom'></a> Arrow Bottom</li>\n<li><a name='arrow-left' class='iconic arrow-left'></a> Arrow Left</li>\n<li><a name='arrow-up-alt' class='iconic arrow-up-alt'></a> Arrow Up (alternate)</li>\n<li><a name='arrow-right-alt' class='iconic arrow-right-alt'></a> Arrow Right (alternate)</li>\n<li><a name='arrow-bottom-alt' class='iconic arrow-bottom-alt'></a> Arrow Bottom (alternate)</li>\n<li><a name='arrow-left-alt' class='iconic arrow-left-alt'></a> Arrow Left (alternate)</li>\n<li><a name='move' class='iconic move'></a> Move</li>\n<li><a name='move-vertical' class='iconic move-vertical'></a> Move Vertical</li>\n<li><a name='move-horizontal' class='iconic move-horizontal'></a> Move Horizontal</li>\n<li><a name='move-alt' class='iconic move-alt'></a> Move (alternate)</li>\n<li><a name='move-vertical-alt' class='iconic move-vertical-alt'></a> Move Vertical (alternate)</li>\n<li><a name='move-horizontal-alt' class='iconic move-horizontal-alt'></a> Move Horizontal (alternate)</li>\n<li><a name='cursor' class='iconic cursor'></a> Cursor</li>\n<li><a name='plus' class='iconic plus'></a> Plus</li>\n<li><a name='plus-alt' class='iconic plus-alt'></a> Plus (alternate)</li>\n<li><a name='minus' class='iconic minus'></a> Minus</li>\n<li><a name='minus-alt' class='iconic minus-alt'></a> Minus (alternate)</li>\n<li><a name='new-window' class='iconic new-window'></a> New Window</li>\n<li><a name='dial' class='iconic dial'></a> Dial</li>\n<li><a name='lightbulb' class='iconic lightbulb'></a> Lightbulb</li>\n<li><a name='link' class='iconic link'></a> Link</li>\n<li><a name='image' class='iconic image'></a> Image</li>\n<li><a name='article' class='iconic article'></a> Article</li>\n<li><a name='read-more' class='iconic read-more'></a> Read More</li>\n<li><a name='headphones' class='iconic headphones'></a> Headphones</li>\n<li><a name='equalizer' class='iconic equalizer'></a> Equalizer</li>\n<li><a name='fullscreen' class='iconic fullscreen'></a> Fullscreen</li>\n<li><a name='exit-fullscreen' class='iconic exit-fullscreen'></a> Exit Fullscreen</li>\n<li><a name='spin' class='iconic spin'></a> Spin</li>\n<li><a name='spin-alt' class='iconic spin-alt'></a> Spin (alternate)</li>\n<li><a name='moon' class='iconic moon'></a> Moon</li>\n<li><a name='sun' class='iconic sun'></a> Sun</li>\n<li><a name='map-pin' class='iconic map-pin'></a> Map Pin</li>\n<li><a name='pin' class='iconic pin'></a> Pin</li>\n<li><a name='eyedropper' class='iconic eyedropper'></a> Eyedropper</li>\n<li><a name='denied' class='iconic denied'></a> Denied</li>\n<li><a name='calendar' class='iconic calendar'></a> Calendar</li>\n<li><a name='calendar-alt' class='iconic calendar-alt'></a> Calendar (alternate)</li>\n<li><a name='bolt' class='iconic bolt'></a> Bolt</li>\n<li><a name='clock' class='iconic clock'></a> Clock</li>\n<li><a name='document' class='iconic document'></a> Document</li>\n<li><a name='book' class='iconic book'></a> Book</li>\n<li><a name='book-alt' class='iconic book-alt'></a> Book (alternate)</li>\n<li><a name='magnifying-glass' class='iconic magnifying-glass'></a> Magnifying Glass</li>\n<li><a name='tag' class='iconic tag'></a> Tag</li>\n<li><a name='heart' class='iconic heart'></a> Heart</li>\n<li><a name='info' class='iconic info'></a> Info</li>\n<li><a name='chat' class='iconic chat'></a> Chat</li>\n<li><a name='chat-alt' class='iconic chat-alt'></a> Chat (alternate)</li>\n<li><a name='key' class='iconic key'></a> Key</li>\n<li><a name='unlocked' class='iconic unlocked'></a> Unlocked</li>\n<li><a name='locked' class='iconic locked'></a> Locked</li>\n<li><a name='mail' class='iconic mail'></a> Mail</li>\n<li><a name='mail' class='iconic mail-alt'></a> Mail (alternate)</li>\n<li><a name='phone' class='iconic phone'></a> Phone</li>\n<li><a name='box' class='iconic box'></a> Box</li>\n<li><a name='pencil' class='iconic pencil'></a> Pencil</li>\n<li><a name='pencil-alt' class='iconic pencil-alt'></a> Pencil (alternate)</li>\n<li><a name='comment' class='iconic comment'></a> Comment</li>\n<li><a name='comment' class='iconic comment-alt'></a> Comment (alternate)</li>\n<li><a name='rss' class='iconic rss'></a> RSS</li>\n<li><a name='star' class='iconic star'></a> Star</li>\n<li><a name='trash' class='iconic trash'></a> Trash</li>\n<li><a name='user' class='iconic user'></a> User</li>\n<li><a name='volume' class='iconic volume'></a> Volume</li>\n<li><a name='mute' class='iconic mute'></a> Mute</li>\n<li><a name='cog' class='iconic cog'></a> Cog</li>\n<li><a name='cog-alt' class='iconic cog-alt'></a> Cog (alternate)</li>\n<li><a name='x' class='iconic x'></a> X</li>\n<li><a name='x' class='iconic x-alt'></a> X (alternate)</li>\n<li><a name='check' class='iconic check'></a> Check</li>\n<li><a name='check-alt' class='iconic check-alt'></a> Check (alternate)</li>\n<li><a name='beaker' class='iconic beaker'></a> Beaker</li>\n<li><a name='beaker-alt' class='iconic beaker-alt'></a> Beaker (alternate)</li>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "_stylus/_nib/iconic/iconic.css",
    "content": "@font-face {\n  font-family: 'IconicStroke';\n    src: url(\"iconic_stroke.eot\");\n    src: local('IconicStroke'),\n       url(\"iconic_stroke.svg#iconic\") format('svg'),\n\t   url(\"iconic_stroke.otf\") format('opentype');\n}\n\n.iconic {\n\tcolor:inherit;\n\tfont-family: \"IconicStroke\";\n}\n\na.iconic:hover {\n\tcolor:inherit;\n}\n\n.iconic.home:before { content: '!'; }\n.iconic.at:before { content: \"@\"; }\n.iconic.quote:before { content: '\"'; }\n.iconic.quote-alt:before { content: \"'\"; }\n.iconic.arrow-up:before { content: \"3\"; }\n.iconic.arrow-right:before { content: \"4\"; }\n.iconic.arrow-bottom:before { content: \"5\"; }\n.iconic.arrow-left:before { content: \"6\"; }\n.iconic.arrow-up-alt:before { content: \"#\"; }\n.iconic.arrow-right-alt:before { content: \"$\"; }\n.iconic.arrow-bottom-alt:before { content: \"%\"; }\n.iconic.arrow-left-alt:before { content: \"^\"; }\n.iconic.move:before { content: \"9\"; }\n.iconic.move-vertical:before { content: \"8\"; }\n.iconic.move-horizontal:before { content: \"7\"; }\n.iconic.move-alt:before { content: \"(\"; }\n.iconic.move-vertical-alt:before { content: \"*\"; }\n.iconic.move-horizontal-alt:before { content: \"&\"; }\n.iconic.cursor:before { content: \")\"; }\n.iconic.plus:before { content: \"+\"; }\n.iconic.plus-alt:before { content: \"=\"; }\n.iconic.minus:before { content: \"-\"; }\n.iconic.minus-alt:before { content: \"_\"; }\n.iconic.new-window:before { content: \"1\"; }\n.iconic.dial:before { content: \"2\"; }\n.iconic.lightbulb:before { content: \"0\"; }\n.iconic.link:before { content: \"/\"; }\n.iconic.image:before { content: \"?\"; }\n.iconic.article:before { content: \">\"; }\n.iconic.read-more:before { content: \".\"; }\n.iconic.headphones:before { content: \",\"; }\n.iconic.equalizer:before { content: \"<\"; }\n.iconic.fullscreen:before { content: \":\"; }\n.iconic.exit-fullscreen:before { content: \";\"; }\n.iconic.spin:before { content: \"[\"; }\n.iconic.spin-alt:before { content: \"{\"; }\n.iconic.moon:before { content: \"]\"; }\n.iconic.sun:before { content: \"}\"; }\n.iconic.map-pin:before { content: \"\\\\\"; }\n.iconic.pin:before { content: \"|\"; }\n.iconic.eyedropper:before { content: \"~\"; }\n.iconic.denied:before { content: \"`\"; }\n.iconic.calendar:before { content: \"a\"; }\n.iconic.calendar-alt:before { content: \"A\"; }\n.iconic.bolt:before { content: \"b\"; }\n.iconic.clock:before { content: \"c\"; }\n.iconic.document:before { content: \"d\"; }\n.iconic.book:before { content: \"e\"; }\n.iconic.book-alt:before { content: \"E\"; }\n.iconic.magnifying-glass:before { content: \"f\"; }\n.iconic.tag:before { content: \"g\"; }\n.iconic.heart:before { content: \"h\"; }\n.iconic.info:before { content: \"i\"; }\n.iconic.chat:before { content: \"j\"; }\n.iconic.chat-alt:before { content: \"J\"; }\n.iconic.key:before { content: \"k\"; }\n.iconic.unlocked:before { content: \"l\"; }\n.iconic.locked:before { content: \"L\"; }\n.iconic.mail:before { content: \"m\"; }\n.iconic.mail-alt:before { content: \"M\"; }\n.iconic.phone:before { content: \"n\"; }\n.iconic.box:before { content: \"o\"; }\n.iconic.pencil:before { content: \"p\"; }\n.iconic.pencil-alt:before { content: \"P\"; }\n.iconic.comment:before { content: \"q\"; }\n.iconic.comment-alt:before { content: \"Q\"; }\n.iconic.rss:before { content: \"r\"; }\n.iconic.star:before { content: \"s\"; }\n.iconic.trash:before { content: \"t\"; }\n.iconic.user:before { content: \"u\"; }\n.iconic.volume:before { content: \"v\"; }\n.iconic.mute:before { content: \"V\"; }\n.iconic.cog:before { content: \"w\"; }\n.iconic.cog-alt:before { content: \"W\"; }\n.iconic.x:before { content: \"x\"; }\n.iconic.x-alt:before { content: \"X\"; }\n.iconic.check:before { content: \"y\"; }\n.iconic.check-alt:before { content: \"Y\"; }\n.iconic.beaker:before { content: \"z\"; }\n.iconic.beaker-alt:before { content: \"Z\"; }\n"
  },
  {
    "path": "_stylus/_nib/index.styl",
    "content": "@import 'lib/nib/'\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/border.styl",
    "content": "\n/*\n * border: <color>\n * border: ...\n */\n\nborder(color, args...)\n  if color is a 'color'\n    border: 1px solid color args\n  else\n    border: arguments\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/clearfix.styl",
    "content": "\n/*\n * The Magnificent Micro Clearfix\n *\n * Useful for clearing floats without structural markup.\n * Prevents margin-collapsing on child elements in most cases.\n *\n * Known issues:\n *\n * 1. For IE 6/7 when applied to an element that contains only left-floated\n *    children the bottom margin on child elements will be collapsed.\n *\n * 2. For Firefox versions prior to 3.5 when applied to the first child element\n *    of body, and the element does not have non-zero padding, extra space will\n *    appear between the body and the first child.\n *\n * See http://nicolasgallagher.com/micro-clearfix-hack/\n * and http://j.mp/bestclearfix\n *\n */\n\nclearfix()\n  &:before\n  &:after\n    content: \"\"\n    display: table\n  &:after\n    clear: both\n  zoom: 1 if support-for-ie\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/color-image.styl",
    "content": "\ncolor-image(color)\n  error('node-canvas is required for color-image()') unless has-canvas\n  colorImage = create-color-image(color)\n  'url(%s)' % color-data-uri(colorImage)\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/config.styl",
    "content": "/*\n * Support for ie defaulting to true.\n */\n\nsupport-for-ie ?= true\n\n/*\n * Default vendor prefixes.\n */\n\nvendor-prefixes ?= webkit moz o ms official\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/flex.styl",
    "content": "/*\n * Vendor \"display: flex\" support with fallback to obsolete versions.\n */\n\nflex-version ?= box flex\n\n//\n// 1. Display values\n//    - http://www.w3.org/TR/css3-flexbox/#flex-containers\n//\ndisplay(type, args...)\n  if flex == type || inline-flex == type\n    if box in flex-version\n      if flex == type\n        display: -ms-flexbox args\n        display: vendor-value(box args, only: moz webkit)\n      else\n        display: -ms-inline-flexbox args\n        display: vendor-value(inline-box args, only: moz webkit)\n    if flex in flex-version\n      display: vendor-value(arguments, only: webkit official) // overwrites old webkit\n  else\n    display: arguments\n\n/*\n * New syntax for browsers like Google Chrome.\n * Plus a translation to the old syntax, if possible.\n */\n\n\n//\n// 5. Ordering and Orientation\n//    - http://www.w3.org/TR/css3-flexbox/#ordering-and-orientation\n//\n-flex-obsolete-direction(direction)\n  if box in flex-version\n    if row-reverse == direction || column-reverse == direction\n      vendor('box-direction', reverse, ignore: ms official)\n\n    if row == direction || row-reverse == direction\n      vendor('box-orient', horizontal, ignore: ms official)\n    else if column == direction || column-reverse == direction\n      vendor('box-orient', vertical, ignore: ms official)\n\n-flex-obsolete-wrap(value)\n  if box in flex-version\n    // WARN: wrap-reverse does not have a box equivalent. This will render in different manners\n    //    on box vs. flex values.\n    if 'wrap' == value || wrap-reverse == value\n      vendor('box-lines', multiple, ignore: ms official)\n    else if nowrap == value\n      vendor('box-lines', single, ignore: ms official)\n\nflex-direction(direction)\n  // obsolete\n  -flex-obsolete-direction(direction)\n\n  // new\n  if flex in flex-version\n    vendor('flex-direction', arguments, only: webkit ms official)\n\nflex-wrap(value)\n  // obsolete\n  -flex-obsolete-wrap(value)\n\n  if flex in flex-version\n    vendor('flex-wrap', arguments, only: webkit ms official)\n\nflex-flow()\n  // obsolete\n  -flex-obsolete-direction(arguments[0])\n  -flex-obsolete-direction(arguments[1])\n  -flex-obsolete-wrap(arguments[0])\n  -flex-obsolete-wrap(arguments[1])\n\n  // new\n  if flex in flex-version\n    vendor('flex-flow', arguments, only: webkit ms official)\n\n\norder()\n  // obsolete\n  if box in flex-version\n    vendor('box-ordinal-group', arguments, ignore: ms official)\n\n  // new\n  if flex in flex-version\n    vendor('flex-order', arguments, only: ms)\n    vendor('order', arguments, only: webkit official)\n\n\n//\n// 7. Flexibility\n//    - http://www.w3.org/TR/css3-flexbox/#flexibility\n//\nflex-grow(growth)\n  // obsolete\n  if box in flex-version\n    vendor('box-flex', growth)\n\n  // new\n  if flex in flex-version\n    vendor('flex-grow', arguments, only: webkit official)\n\nflex-basis()\n  if flex in flex-version\n    vendor('flex-basis', arguments, only: webkit official)\n\nflex-shrink()\n  if flex in flex-version\n    vendor('flex-shrink', arguments, only: webkit official)\n\nflex(growth)\n\n  // obsolete\n  if box in flex-version\n    shrink = 1\n\n    if none == growth || initial == growth\n      // Well known values\n      shrink = 0 if none == growth\n      growth = 0\n    else if is-width(growth) == true\n      // Basis is defined as the first parameter\n      growth = arguments[1] || 0\n      shrink = arguments[2] if 3 <= length(arguments)\n    else if arguments[1] && is-width(arguments[1]) == false\n      // Growth is first and shrink is second\n      shrink = arguments[1]\n\n    // Since we can't make the distinction between growing and shrinking in the box model, take\n    // the one that provides the most flexibility.\n    vendor('box-flex', max(growth, shrink), ignore: ms)\n\n  // new\n  if flex in flex-version\n    vendor('flex', arguments, only: webkit ms official)\n\n\n// converts the justification alignment\n-convert-justify(align)\n  if flex-start == align\n    return start\n  else if flex-end == align\n    return end\n  else if space-around == align\n    return distribute\n  else if space-between == align\n    return justify\n  else\n    return align\n\n//\n// 8. Alignment\n//    - http://www.w3.org/TR/css3-flexbox/#alignment\n//\njustify-content(align)\n  // obsolete\n  if box in flex-version\n    vendor('box-pack', -convert-justify(align), ignore: ms official)\n\n  // new\n  if flex in flex-version\n    vendor('flex-pack', -convert-justify(align), only: ms)\n    vendor('justify-content', align, only: webkit official)\n\nalign-content(align)\n  // WARN: Obsolete spec does not allow for adjustment here\n  if flex in flex-version\n    vendor('flex-line-pack', -convert-justify(align), only: ms)\n    vendor('align-content', align, only: webkit official)\n\n// converts alignment from 'flex' to normal value\n-convert-alignment(align)\n  if flex-start == align\n    return start\n  else if flex-end == align\n    return end\n  else\n    return align\n\nalign-items(align)\n  // obsolete\n  if box in flex-version\n    vendor('box-align', -convert-alignment(align), ignore: ms official)\n\n  // new\n  if flex in flex-version\n    vendor('flex-align', -convert-alignment(align), only: ms)\n    vendor('align-items', arguments, only: webkit official)\n\nalign-self(align)\n  // WARN: Obsolete spec does not allow for overriding alignment on individual items.\n  if flex in flex-version\n    vendor('align-self', align, only: webkit official)\n    vendor('flex-item-align', -convert-alignment(align), only: ms)\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/gradients.styl",
    "content": "\n@import 'config'\n\n/*\n * Implicit color stop position.\n */\n\npos-in-stops(i, stops)\n  len = length(stops)\n  if len - 1 == i\n    100%\n  else if i\n    unit(i / len * 100, '%')\n  else\n    0\n\n/*\n * Normalize color stops:\n *\n *   - (color pos) -> (pos color)\n *   - (color) -> (implied-pos color)\n *\n */\n\nnormalize-stops(stops)\n  stops = clone(stops)\n  for stop, i in stops\n    if length(stop) == 1\n      color = stop[0]\n      stop[0] = pos-in-stops(i, stops)\n      stop[1] = color\n    else if typeof(stop[1]) == 'unit'\n      pos = stop[1]\n      stop[1] = stop[0]\n      stop[0] = pos\n  stops\n\n/*\n * Join color stops with the given translation function.\n */\n\njoin-stops(stops, translate)\n  str = ''\n  len = length(stops)\n  for stop, i in stops\n    str += ', ' if i\n    pos = stop[0]\n    color = stop[1]\n    str += translate(color, pos)\n  unquote(str)\n\n/*\n * Standard color stop.\n */\n\nstd-stop(color, pos)\n  '%s %s' % (color pos)\n\n/*\n * Create a linear gradient with the given start position\n * and variable number of color stops.\n *\n * Examples:\n *\n *    background: linear-gradient(top, red, green, blue)\n *    background: linear-gradient(bottom, red, green 50%, blue)\n *    background: linear-gradient(bottom, red, 50% green, blue)\n *    background: linear-gradient(bottom, red, 50% green, 90% white, blue)\n *\n */\n\nlinear-gradient(start, stops...)\n  error('color stops required') unless length(stops)\n\n  unquote('linear-gradient(' + join(', ',arguments) + ')')\n\n/*\n * Create a linear gradient image with the given start position\n * and variable number of color stops.\n */\n\nlinear-gradient-image(start, stops...)\n  error('node-canvas is required for linear-gradient-image()') unless has-canvas\n  stops = stops[0] if length(stops) == 1\n  error('gradient image size required') unless start[0] is a 'unit'\n  size = start[0]\n  start = start[1] or 'top'\n  grad = create-gradient-image(size, start)\n  stops = normalize-stops(stops)\n  add-color-stop(grad, stop[0], stop[1]) for stop in stops\n  'url(%s)' % gradient-data-uri(grad)\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/iconic.styl",
    "content": "\niconic-stroke(path)\n  @font-face\n    font-family: 'IconicStroke'\n    src: url(path + '/iconic_stroke.eot')\n    src: local('☺'), url(path + '/iconic_stroke.ttf') format('truetype'), url(path + '/iconic_stroke.svg#iconic') format('svg')\n    font-weight: normal\n    font-style: normal\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/image.styl",
    "content": "\n/*\n * Define background-image as `path` with optional width and height, adding an\n * @2x variant.\n *\n * affected by github.com/LearnBoost/stylus/issues/1050 and\n * github.com/LearnBoost/stylus/issues/1038 ... refactor when those are closed\n */\n\nimage(path, w = auto, h = auto, min_pixel_ratio = 1.5)\n  background-image: url(path)\n\n  s = 'all and (-webkit-min-device-pixel-ratio:' + min_pixel_ratio + '),'\n  s = s + '(min--moz-device-pixel-ratio:' + min_pixel_ratio + '),'\n  s = s + '(-o-min-device-pixel-ratio:' + min_pixel_ratio + '/1),'\n  s = s + '(min-device-pixel-ratio:' + min_pixel_ratio + '),'\n  s = s + '(min-resolution:' + unit(min_pixel_ratio*92, dpi) + '),'\n  s = s + '(min-resolution:' + unit(min_pixel_ratio, dppx) + ')'\n\n  @media s\n    ext = extname(path)\n    path = pathjoin(dirname(path), basename(path, ext) + '@2x' + ext)\n    background-image: url(path)\n    if w in (cover contain) and h == auto\n        h = null\n    background-size: w h\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/index.styl",
    "content": "@import 'border'\n@import 'clearfix'\n@import 'color-image'\n@import 'flex'\n@import 'gradients'\n@import 'iconic'\n@import 'image'\n@import 'overflow'\n@import 'positions'\n@import 'reset'\n@import 'text'\n@import 'vendor'\n@import 'size'\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/overflow.styl",
    "content": "/*\n * Overflow utility. Maps to regular overflow, and adds an ellipsis value.\n *\n * Synopsis:\n *\n *   overflow: <type>\n *\n * Examples:\n *\n *     overflow: auto\n *     overflow: hidden\n *     overflow: ellipsis\n *\n */\n\noverflow()\n  if arguments[0] == ellipsis\n    ellipsis()\n  else\n    overflow: arguments\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/positions.styl",
    "content": "// helper\n\n-pos(type, args)\n  i = 0\n  position: unquote(type)\n  for j in (1..4)\n    if length(args) > i\n      {args[i]}: args[i + 1] is a 'unit' ? args[i += 1] : 0\n    i += 1\n\n/*\n * Position utility.\n * \n * Synopsis:\n * \n *   fixed: <pos> [n] <pos> [n]\n * \n * Examples:\n * \n *     fixed: top left\n *     fixed: top 5px left\n *     fixed: top left 5px\n *     fixed: top 5px left 5px\n * \n */\n\nfixed()\n  -pos('fixed', arguments)\n\n/*\n * Position utility.\n * \n * Synopsis:\n * \n *   absolute: <pos> [n] <pos> [n]\n * \n * Examples:\n * \n *     absolute: top left\n *     absolute: top 5px left\n *     absolute: top left 5px\n *     absolute: top 5px left 5px\n * \n */\n\nabsolute()\n  -pos('absolute', arguments)\n\n/*\n * Position utility.\n * \n * Synopsis:\n * \n *   relative: <pos> [n] <pos> [n]\n * \n * Examples:\n * \n *     relative: top left\n *     relative: top 5px left\n *     relative: top left 5px\n *     relative: top 5px left 5px\n * \n */\n\nrelative()\n  -pos('relative', arguments)\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/reset.styl",
    "content": "// Based on [Eric Meyer's reset](http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/)\n\nglobal-reset()\n  html, body, div, span, applet, object, iframe,\n  h1, h2, h3, h4, h5, h6, p, blockquote, pre,\n  a, abbr, acronym, address, big, cite, code,\n  del, dfn, em, img, ins, kbd, q, s, samp,\n  small, strike, strong, sub, sup, tt, var,\n  dl, dt, dd, ol, ul, li,\n  fieldset, form, label, legend,\n  table, caption, tbody, tfoot, thead, tr, th, td\n    reset-box-model()\n    reset-font()\n  body\n    reset-body()\n  ol, ul\n    list-style: none\n  table\n    reset-table()\n  caption, th, td\n    reset-table-cell()\n  a img\n    border: none\n\nnested-reset()\n  div, span, object, iframe, h1, h2, h3, h4, h5, h6, p,\n  pre, a, abbr, acronym, address, code, del, dfn, em, img,\n  dl, dt, dd, ol, ul, li, fieldset, form, label,\n  legend, caption, tbody, tfoot, thead, tr\n    reset-box-model()\n    reset-font()\n  table\n    reset-table()\n  caption, th, td\n    reset-table-cell()\n  a img\n    border: none\n\nreset-box-model()\n  margin: 0\n  padding: 0\n  border: 0\n  outline: 0\n\nreset-font()\n  font-weight: inherit\n  font-style: inherit\n  font-family: inherit\n  font-size: 100%\n  vertical-align: baseline\n\nreset-body()\n  line-height: 1\n  color: black\n  background: white\n\nreset-table()\n  border-collapse: separate\n  border-spacing: 0\n  vertical-align: middle\n\nreset-table-cell()\n  text-align: left\n  font-weight: normal\n  vertical-align: middle\n\nreset-html5()\n  article, aside, canvas, details, figcaption,\n  figure, footer, header, hgroup, menu, nav,\n  section, summary, main\n    reset-box-model()\n    display: block\n  audio, canvas, video\n    display inline-block\n    *display inline\n    *zoom 1\n  audio:not([controls]),[hidden]\n    display none\n  \n"
  },
  {
    "path": "_stylus/_nib/lib/nib/size.styl",
    "content": "/*\n * Size utility.\n * \n * Synopsis:\n * \n *   size: <width> <height> | <width & height>\n * \n * Examples:\n * \n *     size: 100% 30px\n *       yields:\n *         width: 100%\n *         height: 30px\n * \n *     size: 5px\n *       yields:\n *         width: 5px\n *         height: 5px\n * \n */\n\nsize()\n  if length(arguments) == 1\n    width: arguments[0]\n    height: arguments[0]\n  else\n    width: arguments[0]\n    height: arguments[1]\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/text/aliases.styl",
    "content": "\n/*\n * Alias of \"nowrap\".\n */\n\nno-wrap = unquote('nowrap')\n\n/*\n * Alias of \"white-space\".\n */\n\nwhitespace()\n  white-space: arguments"
  },
  {
    "path": "_stylus/_nib/lib/nib/text/ellipsis.styl",
    "content": "\n/*\n * Ellipsis with wrapping disabled by default.\n */\n\nellipsis(no-wrap = true)\n  if no-wrap\n    white-space: nowrap\n  overflow: hidden\n  text-overflow: ellipsis"
  },
  {
    "path": "_stylus/_nib/lib/nib/text/hide-text.styl",
    "content": "/*\n * Hide text.\n */\n\nhide-text()\n  text-indent: 101%\n  white-space: nowrap\n  overflow: hidden"
  },
  {
    "path": "_stylus/_nib/lib/nib/text/index.styl",
    "content": "@import './aliases'\n@import './ellipsis'\n@import './hide-text'\n@import './replace-text'\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/text/replace-text.styl",
    "content": "/*\n * Replace text with an image.\n */\n\nreplace-text(image, x=50%, y=50%)\n  hide-text()\n  background-image image\n  background-repeat no-repeat\n  background-position x y\n"
  },
  {
    "path": "_stylus/_nib/lib/nib/vendor.styl",
    "content": "use('../nodes/vendor-helpers.js')\n@import 'config'\n\n/*\n * Alias \"nowrap\" as \"no-wrap\".\n */\n\nno-wrap = unquote('nowrap')\n\n/*\n * Helper to find out if a given value is a width\n */\n\nis-width(val)\n  if auto == val\n    return true\n  else if val && 'unit' == type(val)\n    // Stylus does not short circuit so we need to perform this as a distinct\n    // operation to prevent errors\n    return '' != unit(val)\n  return false\n\n/*\n * Vendor support for the given prop / arguments, optionally specifying the\n * only prefixes to utilize, or those which should be ignored.\n */\n\nvendor(prop, args, only = null, ignore = null, vendor-property = true)\n  need_normalize = !vendor-property or prop in ('transition' 'transition-property' 'border-image' 'border-image-slice')\n  for prefix in vendor-prefixes\n    unless (only and !(prefix in only)) or (ignore and prefix in ignore)\n      if official == prefix\n        if need_normalize\n          {prop}: normalize(prop,('%s' % args))\n        else\n          {prop}: args\n      else\n        newprop = prop\n        newprop = '-' + prefix + '-' + prop if vendor-property\n\n        if need_normalize\n          {newprop}: normalize(prop,('%s' % args),prefix)\n        else\n          {newprop}: args\n/*\n * Vendorize the given value.\n */\n\nvendor-value(arg, only = null, ignore = null)\n  prop = current-property[0]\n  for prefix in vendor-prefixes\n    unless (only and !(prefix in only)) or (ignore and prefix in ignore) or official == prefix\n      add-property(prop, '-%s-%s' % (prefix arg))\n  arg\n\n/*\n * Vendor \"box-shadow\" support.\n */\n\nbox-shadow()\n  vendor('box-shadow', arguments, only: webkit official)\n\n/*\n * Vendor \"user-select\" support.\n */\n\nuser-select()\n  vendor('user-select', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"column-count\" support.\n */\n\ncolumn-count()\n  vendor('column-count', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-gap\" support.\n */\n\ncolumn-gap()\n  vendor('column-gap', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-rule\" support.\n */\n\ncolumn-rule()\n  vendor('column-rule', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-rule-color\" support.\n */\n\ncolumn-rule-color()\n  vendor('column-rule-color', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-rule-width\" support.\n */\n\ncolumn-rule-width()\n  vendor('column-rule-width', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-rule-style\" support.\n */\n\ncolumn-rule-style()\n  vendor('column-rule-style', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-width\" support.\n */\n\ncolumn-width()\n  vendor('column-width', arguments, only: webkit moz official)\n\n/*\n * Vendor \"column-span\" support.\n */\n\ncolumn-span()\n  vendor('column-span', arguments, only: webkit official)\n\n/*\n * Vendor \"column-fill\" support.\n */\n\ncolumn-fill()\n  vendor('column-fill', arguments, only: moz)\n\n/*\n * Legacy syntax support for background-clip and background-origin\n */\n\nlegacy-bg-values(property, args)\n  legacy_args = ()\n  importance = unquote('')\n  for subargs in args\n    for arg in subargs\n      if arg in (border-box padding-box content-box)\n        arg = unquote('border')  if arg == border-box\n        arg = unquote('padding') if arg == padding-box\n        arg = unquote('content') if arg == content-box\n      if arg != '!important'\n        push(legacy_args,arg)\n      else\n        importance = !important\n  vendor(property, unquote(join(', ',legacy_args)) importance, only: moz webkit)\n\n/*\n * Vendor \"background-clip\" support.\n */\n\nbackground-clip()\n  if arguments[0] == text\n    vendor('background-clip', arguments, only: webkit)\n  else\n    legacy-bg-values('background-clip', arguments)\n    background-clip: arguments\n\n/*\n * Vendor \"background-origin\" support.\n */\n\nbackground-origin()\n  legacy-bg-values('background-origin', arguments)\n  background-origin: arguments\n\n/*\n * Vendor \"background-size\" support.\n */\n\nbackground-size()\n  vendor('background-size', arguments, only: webkit moz official)\n\n/*\n * Vendor \"transform\" support.\n */\n\ntransform()\n  vendor('transform', arguments)\n\n/*\n * Vendor \"transform-origin\" support.\n */\ntransform-origin()\n    vendor('transform-origin', arguments)\n\n/*\n * Vendor \"transform-style\" support.\n */\n\ntransform-style()\n  vendor('transform-style', arguments)\n\n/*\n * Vendor \"border-image\" support.\n */\n\nborder-image()\n  vendor('border-image', arguments, only: webkit moz o official)\n\n/*\n * Vendor \"transition\" support.\n */\n\ntransition()\n  vendor('transition', arguments)\n\n/*\n * Vendor \"transition-property\" support.\n */\n\ntransition-property()\n  vendor('transition-property', arguments)\n\n/*\n * Vendor \"transition-duration\" support.\n */\n\ntransition-duration()\n  vendor('transition-duration', arguments)\n\n/*\n * Vendor \"transition-timing-function\" support.\n */\n\ntransition-timing-function()\n  vendor('transition-timing-function', arguments)\n\n/*\n * Vendor \"transition-delay\" support.\n */\n\ntransition-delay()\n  vendor('transition-delay', arguments)\n\n/*\n * Vendor \"backface-visibility\" support.\n */\n\nbackface-visibility()\n  vendor('backface-visibility', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"perspective\" support.\n */\n\nperspective()\n  if mixin\n    vendor('perspective', arguments, only: webkit moz ms official)\n  else\n    'perspective(%s)' % arguments\n\n/*\n * Vendor \"perspective-origin\" support.\n */\n\nperspective-origin()\n  vendor('perspective-origin', arguments, only: webkit moz ms official)\n\n/*\n * Opacity with conditional IE support.\n */\n\nopacity(n, args...)\n  opacity: n args\n  if support-for-ie\n    val = round(n * 100)\n    if val == 100\n      -ms-filter: none\n      filter: none\n    else\n      -ms-filter: '\"progid:DXImageTransform.Microsoft.Alpha(Opacity=%s)\"' % val args\n      filter: 'alpha(opacity=%s)' % val args\n\n/*\n * Vendor \"text-size-adjust\"\n */\n\ntext-size-adjust()\n  vendor('text-size-adjust', arguments)\n\n/*\n * Alias the \"white-space\" property.\n */\n\nwhitespace()\n  white-space: arguments\n\n/*\n * Vendor \"box-sizing\" support.\n */\n\nbox-sizing()\n  vendor('box-sizing', arguments, only: webkit moz official)\n\n/*\n * Vendor \"box-orient\" support.\n */\n\nbox-orient()\n  vendor('box-orient', arguments, only: webkit moz official)\n\n/*\n * Vendor \"box-flex-group\" support.\n */\n\nbox-flex-group()\n  vendor('box-flex-group', arguments, only: webkit moz official)\n\n/*\n * Vendor \"box-ordinal-group\" support.\n */\n\nbox-ordinal-group()\n  vendor('box-ordinal-group', arguments, only: webkit moz ms official)\n\n\n/*\n * Vendor \"box-align\" support.\n */\n\nbox-align()\n  vendor('box-align', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"box-pack\" support.\n */\n\nbox-pack()\n  vendor('box-pack', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"box-direction\" support.\n */\n\nbox-direction()\n  vendor('box-direction', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"animation\" support.\n */\n\nanimation()\n  vendor('animation', arguments)\n\n\n/*\n * Vendor \"animation-name\" support.\n */\n\nanimation-name()\n  vendor('animation-name', arguments)\n\n/*\n * Vendor \"animation-duration\" support.\n */\n\nanimation-duration()\n  vendor('animation-duration', arguments)\n\n/*\n * Vendor \"animation-delay\" support.\n */\n\nanimation-delay()\n  vendor('animation-delay', arguments)\n\n/*\n * Vendor \"animation-direction\" support.\n */\n\nanimation-direction()\n  vendor('animation-direction', arguments)\n\n/*\n * Vendor \"animation-iteration-count\" support.\n */\n\nanimation-iteration-count()\n  vendor('animation-iteration-count', arguments)\n\n/*\n * Vendor \"animation-timing-function\" support.\n */\n\nanimation-timing-function()\n  vendor('animation-timing-function', arguments)\n\n/*\n * Vendor \"animation-play-state\" support.\n */\n\nanimation-play-state()\n  vendor('animation-play-state', arguments)\n\n/*\n * Vendor \"animation-fill-mode\" support.\n */\n\nanimation-fill-mode()\n  vendor('animation-fill-mode', arguments)\n\n/*\n * Vendor \"hyphens\" support.\n */\n\nhyphens()\n  vendor('hyphens', arguments, only: webkit moz ms official)\n\n/*\n * Vendor \"appearance\" support.\n */\n\nappearance()\n  vendor('appearance', arguments, only: webkit moz official)\n\n/*\n * Vendor \"tab-size\" support.\n */\n\ntab-size()\n  vendor('tab-size', arguments, only: moz o official)\n\n/*\n * Vendor \"overflow-scrolling\" support.\n */\n\noverflow-scrolling()\n  vendor('overflow-scrolling', arguments, only: webkit official)\n\n/*\n * Vendor \"text-overflow\" support, , -o- for opera 9.* - 10.*\n */\n\ntext-overflow()\n  vendor('text-overflow', arguments, only: official o)\n\n/*\n * Vendor \"text-size-adjust\" support.\n */\ntext-size-adjust()\n  vendor('text-size-adjust', arguments, only: official webkit ms)\n\n/*\n * Vendor \"font-smoothing\" support, webkit only.\n */\nfont-smoothing()\n  vendor('font-smoothing', arguments, only: webkit)\n\n/*\n * Helper for border-radius().\n */\n\n-apply-border-radius(pos, importance)\n  if length(pos) == 3\n    // border-radius: <top | buttom> <left | right> <n>\n    y = pos[0]\n    x = pos[1]\n    // We don't use moz for simple boder-radius anymore\n    // vendor('border-radius-%s%s' % pos, pos[2], only: moz)\n    vendor('border-%s-%s-radius' % pos, pos[2] importance, only: webkit official)\n  else if pos[0] in (top bottom)\n    // border-radius: <top | bottom> <n>\n    -apply-border-radius(pos[0] left pos[1], importance)\n    -apply-border-radius(pos[0] right pos[1], importance)\n  else if pos[0] in (left right)\n    // border-radius: <left | right> <n>\n    unshift(pos, top);\n    -apply-border-radius(pos, importance)\n    pos[0] = bottom\n    -apply-border-radius(pos, importance)\n\n/*\n * border-radius supporting vendor prefixes and\n * augmented behavior.\n *\n * Examples:\n *\n *    border-radius: 2px 5px\n *    border-radius: top 5px bottom 10px\n *    border-radius: left 5px\n *    border-radius: top left 5px\n *    border-radius: top left 10px bottom right 5px\n *    border-radius: top left 10px, bottom right 5px\n *\n */\n\nborder-radius()\n  pos = ()\n  augmented = false\n  importance = arguments[length(arguments) - 1] == !important ? !important : unquote('')\n\n  for args in arguments\n    for arg in args\n      if arg is a 'ident'\n        append(pos, arg)\n        augmented = true\n      else\n        append(pos, arg)\n        if augmented\n          -apply-border-radius(pos, importance)\n          pos = ()\n  vendor('border-radius', pos, only: webkit official) unless augmented\n\n/**\n * Vendor input-placeholder/placeholder support.\n *\n * Examples:\n *    // Default syntax\n *    body\n *      placeholder(color #333, font-weight normal)\n *\n *    // The comma is important\n *    .placeholder-red\n *      placeholder(color red,)\n *\n *    // We can pass a function\n *    green-placeholder()\n *      color green\n *    .placeholder-green\n *      placeholder(green-placeholder)\n *\n *    // We can pass a hash\n *    textarea\n *      placeholder((font-style italic) (font-weight bold) (padding '4px 10px'))\n */\nplaceholder()\n  for v in ':-webkit-input' '-moz' ':-moz' '-ms-input'\n    &:{v}-placeholder\n      for pair in arguments\n        if typeof(pair) == 'function'\n          pair()\n        else if pair is not null && pair[0] is not null\n          {pair[0]}: type(pair[1]) == 'string' ? s(pair[1]) : pair[1]\ninput-placeholder = placeholder\n\n/*\n * Vendor background support (gradients).\n */\n\nbackground()\n  if match('-gradient\\(', ''+arguments)\n    vendor('background', arguments, vendor-property: false)\n  else\n    background arguments\n\nbackground-image()\n  if match('-gradient\\(', ''+arguments)\n    vendor('background-image', arguments, vendor-property: false)\n  else\n    background-image arguments\n\ncursor()\n  if match('-gradient\\(', ''+arguments)\n    vendor('cursor', arguments, vendor-property: false)\n  else\n    cursor arguments\n\nlist-style()\n  if match('-gradient\\(', ''+arguments)\n    vendor('list-style', arguments, vendor-property: false)\n  else\n    list-style arguments\n\nlist-style-image()\n  if match('-gradient\\(', ''+arguments)\n    vendor('list-style-image', arguments, vendor-property: false)\n  else\n    list-style-image arguments\n"
  },
  {
    "path": "_stylus/_nib/lib/nib.js",
    "content": "\n/*!\n * nib\n * Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar stylus = require('stylus')\n  , path = require('path')\n  , nodes = stylus.nodes\n  , utils = stylus.utils\n  , Canvas\n\nexports = module.exports = plugin;\n\n// conditionally expose canvas-based APIs.\n\ntry {\n  Canvas = require('canvas');\n\n  var gradient = require('./nodes/gradient')\n    , colorImage = require('./nodes/color-image')\n} catch (err) {\n  // ignore\n}\n\n/**\n * Library version.\n */\n\nexports.version = require(path.join(__dirname, '../package.json')).version;\n\n/**\n * Stylus path.\n */\n\nexports.path = __dirname;\n\n/**\n * Return the plugin callback for stylus.\n *\n * @return {Function}\n * @api public\n */\n\nfunction plugin() {\n  return function(style){\n    style.include(__dirname);\n\n    if (Canvas) {\n      style.define('has-canvas', nodes.true);\n\n      // gradients\n      style.define('create-gradient-image', gradient.create)\n      style.define('gradient-data-uri', gradient.dataURL)\n      style.define('add-color-stop', gradient.addColorStop)\n\n      // color images\n      style.define('create-color-image', colorImage.create)\n      style.define('color-data-uri', colorImage.dataURL);\n    } else {\n      style.define('has-canvas', nodes.false);\n    }\n  }\n}\n"
  },
  {
    "path": "_stylus/_nib/lib/nodes/color-image.js",
    "content": "\n/**\n * Module dependencies.\n */\n\nvar stylus = require('stylus')\n  , Canvas = require('canvas')\n  , nodes = stylus.nodes\n  , utils = stylus.utils\n\n/**\n * Expose `ColorImage`.\n */\n\nexports = module.exports = ColorImage;\n\n/**\n * Create a new `ColorImage` node with the given `color`.\n *\n * @param {Color} color node\n * @return {ColorImage}\n * @api public\n */\n\nexports.create = function(color){\n  utils.assertColor(color);\n  return new ColorImage(color);\n};\n\n/**\n * Return the data URI for `colorImage`.\n *\n * @param {ColorImage} colorImage\n * @return {String}\n * @api public\n */\n\nexports.dataURL = function(colorImage){\n  utils.assertType(colorImage, 'colorimage');\n  return new nodes.String(colorImage.toDataURL());\n};\n\n/**\n * Initialize a new `ColorImage` node with the given arguments.\n *\n * @param {Color} color node\n * @api private\n */\n\nfunction ColorImage(color) {\n  this.color = color;\n  this.canvas = new Canvas(1, 1);\n  this.ctx = this.canvas.getContext('2d');\n  this.ctx.fillStyle = color.toString();\n  this.ctx.fillRect(0, 0, 1, 1);\n};\n\n/**\n * Inherit from `nodes.Node.prototype`.\n */\n\nColorImage.prototype.__proto__ = nodes.Node.prototype;\n\n/**\n * Inspect the color.\n *\n * @return {String}\n * @api private\n */\n\nColorImage.prototype.toString = function(){\n  return 'ColorImage(' + this.color.toString() + ')';\n};\n\n/**\n * Return data URI string.\n *\n * @return {String}\n * @api private\n */\n\nColorImage.prototype.toDataURL = function(){\n  return this.canvas.toDataURL();\n};\n"
  },
  {
    "path": "_stylus/_nib/lib/nodes/gradient.js",
    "content": "\n/**\n * Module dependencies.\n */\n\nvar stylus = require('stylus')\n  , Canvas = require('canvas')\n  , nodes = stylus.nodes\n  , utils = stylus.utils;\n\n/**\n * Expose `Gradient`.\n */\n\nexports = module.exports = Gradient;\n\n/**\n * Create a new `Gradient` node with the given `size`\n * and `start` position.\n *\n * @param {Number} size\n * @param {String|Ident|Literal} start\n * @return {Gradient}\n * @api public\n */\n\nexports.create = function(size, start){\n  utils.assertType(size, 'unit', 'size');\n  utils.assertString(start, 'start');\n  return new Gradient(size.val, start.string);\n};\n\n/**\n * Add color stop to `grad`.\n *\n * @param {Gradient} grad\n * @param {Unit} pos\n * @param {HSLA|RGBA} color\n * @return {Null}\n * @api public\n */\n\nexports.addColorStop = function(grad, pos, color){\n  utils.assertType(grad, 'gradient', 'grad');\n  utils.assertType(pos, 'unit', 'pos');\n  utils.assertColor(color, 'color');\n  grad.addColorStop(pos.val / 100, color.rgba.toString());\n  return nodes.null;\n};\n\n/**\n * Return the data URI for `grad`.\n *\n * @param {Gradient} grad\n * @return {String}\n * @api public\n */\n\nexports.dataURL = function(grad){\n  utils.assertType(grad, 'gradient');\n  return new nodes.String(grad.toDataURL());\n};\n\n/**\n * Initialize a new `Gradient` node with the given `size`\n * and `start` position.\n *\n * @param {Number} size\n * @param {String} start\n * @api private\n */\n\nfunction Gradient(size, start) {\n  this.size = size;\n  this.canvas = new Canvas(1, 1);\n  this.setStartPosition(start);\n  this.ctx = this.canvas.getContext('2d');\n  this.grad = this.ctx.createLinearGradient(\n      this.from[0], this.from[1]\n    , this.to[0], this.to[1]);\n};\n\n/**\n * Inspect the gradient.\n *\n * @return {String}\n * @api private\n */\n\nGradient.prototype.toString = function(){\n  return 'Gradient(' + this.size + 'px '\n    + this.stops.map(function(stop){\n    return stop[0] + ' ' + stop[1];\n  }).join(', ') + ')';\n};\n\n/**\n * Set `start` position.\n *\n * @param {String} start\n * @api private\n */\n\nGradient.prototype.setStartPosition = function(start){\n  var size = this.size\n    , canvas = this.canvas;\n\n  switch (start) {\n    case 'top':\n      canvas.height = size;\n      this.from = [canvas.width / 2, 0];\n      this.to = [canvas.width / 2, canvas.height];\n      break;\n    case 'bottom':\n      canvas.height = size;\n      this.from = [canvas.width / 2, canvas.height];\n      this.to = [canvas.width / 2, 0];\n      break;\n    case 'left':\n      canvas.width = size;\n      this.from = [0, 0];\n      this.to = [canvas.width, canvas.height];\n      break;\n    case 'right':\n      canvas.width = size;\n      this.from = [canvas.width, canvas.height];\n      this.to = [0, 0];\n      break;\n    default:\n      throw new Error('invalid start position \"' + start + '\"');\n  }\n};\n\n/**\n * Add color stop `pos` / `color`.\n *\n * @param {Number} pos\n * @param {String} color\n * @api private\n */\n\nGradient.prototype.addColorStop = function(pos, color){\n  this.grad.addColorStop(pos, color);\n};\n\n/**\n * Return data URI string.\n *\n * @return {String}\n * @api private\n */\n\nGradient.prototype.toDataURL = function(){\n  var canvas = this.canvas\n    , ctx = this.ctx;\n  ctx.fillStyle = this.grad;\n  ctx.fillRect(0, 0, canvas.width, canvas.height);\n  return canvas.toDataURL();\n};\n\n/**\n * Inherit from `nodes.Node.prototype`.\n */\n\nGradient.prototype.__proto__ = nodes.Node.prototype;\n"
  },
  {
    "path": "_stylus/_nib/lib/nodes/vendor-helpers.js",
    "content": "var RE_GRADIENT_STOPS = /([\\(\\,]\\s*)(-?(?:\\d*\\.)?\\d+(?:%|px|em))(\\s+)((hsl|rgb)a?\\([^\\)]+\\)|#[^\\)\\,]+)/g\n  , RE_GRADIENT_VAL = /(\\(\\s*)(?:(-?(\\d*\\.)?\\d+)deg|((to )?(top|bottom|left|right)( (top|bottom|left|right))?))/g\n  , RE_GRADIENT_TYPE = /((repeating-)?(linear|radial)-gradient\\()/g\n  , RE_TRANSFORM = /\\b(transform)\\b/g\n  , RE_FILL_KEYWORD = /\\s*\\b(fill)\\b\\s*/g;\n\nvar DIRECTIONS = { top: 'bottom', bottom: 'top', left: 'right', right:'left' };\n\n/**\n * Expose `normalize`.\n */\n\nfunction normalize(property, value, prefix){\n  var result = value.toString()\n    , args;\n\n  /* Fixing the gradients */\n  if (~result.indexOf('gradient(')) {\n\n    /* Normalize color stops */\n    result = result.replace(RE_GRADIENT_STOPS,'$1$4$3$2');\n\n    /* Normalize legacy gradients */\n    result = result.replace(RE_GRADIENT_VAL, function(){\n        args = [].slice.call(arguments, 1);\n        return normalizeGradient(args, prefix);\n    });\n\n    /* Adding prefixes to the legacy gradients */\n    if (prefix) result = result.replace(RE_GRADIENT_TYPE, '-' + prefix + '-$1');\n  }\n\n  /* Adding prefixes to the `transform` values of legacy `transition` property */\n  if (prefix && (property == \"'transition'\" || property == \"'transition-property'\")) {\n    result = result.replace(RE_TRANSFORM, '-' + prefix + '-$1');\n  }\n\n  /* Removing `fill` keyword from the legacy `border-image` property */\n  if (prefix && (property == \"'border-image'\" || property == \"'border-image-slice'\")) {\n    result = result.replace(RE_FILL_KEYWORD, ' ');\n  }\n\n  return result;\n}\n\nfunction normalizeGradient(parts, prefix){\n  /* Fix the degrees to the legacy syntax */\n  var val = parts[0];\n\n  // when the gradients were unprefixed, the w3c changed the way that the\n  // angle direction is interpreted. see:\n  // http://blogs.msdn.com/b/ie/archive/2012/06/25/unprefixed-css3-gradients-in-ie10.aspx\n  if (parts[1]) val += (prefix ? parseFloat((Math.abs(450 - parts[1]) % 360).toFixed(3)) : parts[1]) + 'deg';\n\n  /* Fix the directions to the legacy syntax */\n  if (prefix && parts[4]) {\n    // `to top` to `bottom` etc.\n    if (parts[5]) val += DIRECTIONS[parts[5]];\n    if (parts[6]) val += ' ' + DIRECTIONS[parts[7]];\n  } else if (!prefix && !parts[4]) {\n    // `top` to `to bottom` etc.\n    if (parts[5]) val += 'to ' + DIRECTIONS[parts[5]];\n    if (parts[6]) val += ' ' + DIRECTIONS[parts[7]];\n  } else {\n    if (parts[3]) val += parts[3];\n  }\n\n  return val;\n}\n\nvar plugin = function(){\n  return function(style){\n    var nodes = this.nodes;\n    style.define('normalize', function(property, value, prefix) {\n      return new nodes.Ident(normalize(property, value, prefix));\n    });\n  };\n};\nmodule.exports = plugin;\n"
  },
  {
    "path": "_stylus/main.styl",
    "content": "@import '_nib'\niconic-stroke('../iconic/')\n\n/**\n * Variables\n */\nshadow__tiny = 0 1px 1px rgba(0,0,0,.15)\nshadow__pressed_effect = 0 1px 0 rgba(255,255,255, .5)\nfont__base = Georgia, 'Times New Roman', serif\nfont__size = 18px\nfont__size_small = 14px\ncolor__bg = #F4F4F4\ncolor__text = #404040\ncolor__text_second = #888\ncolor__link = #0066CC\ncolor__link_visited = #550066\ncolor__blue = #B4D2F0\ncolor__blue_dark = #99B3CC\ncolor__yellow = #F0E9B4\ncolor__yellow_dark = #CCC699\nimg__noise = url('/assets/img/noise.png')\n\n*\n  box-sizing: border-box\n\nhtml\nbody\n  margin 0\n  height 100%\n\nhtml\n  font-family font__base\n  font-size font__size\n\n\nbody\n  reset-body()\n  background img__noise color__bg\n  color color__text\n  text-shadow shadow__pressed_effect\n\n\nh1\nh2\nh3\nh4\nh5\n  reset-font()\n  reset-box-model()\n  margin-bottom .5em\n  small\n    font-size .6em\n    color color__text_second\n\nh1\n  font-size 2em\n\nh2\n  font-size 1.8em\n\nh3\n  font-size 1.3em\n\nh4\n  font-size 1.2em\n\nh5\n  font-size 1em\n  font-weight bold\n\nul\nol\n  margin 1em 0\n\na\n  // display inline-block\n  padding: 0.6em; // Увеличение зоны нажатия\n  margin: -0.6em; // для планшетов\n  color color__link\n  text-decoration none\n  &:hover\n    text-decoration underline\n  &:visited\n    color color__link_visited\n    &.ignore-visited\n      color color__link\n\n.wrapper\n  width 720px\n  margin 0 auto\n  padding 4em 0 1em\n  position relative\n  min-height 100%\n\n.widget\n  size 728px 90px\n  margin-bottom 1em\n  background-color #fff\n  box-shadow shadow__tiny\n\n.lwidget\n  size 160px 600px\n  // background-color #fff\n  absolute left 100%\n  margin-left 36px\n  // box-shadow shadow__tiny\n\n.money .money__wrapper\n  width 508px\n  height 105px\n  margin 0 auto\n\n.money\n  margin-bottom 1em\n\n.footer\n  // absolute bottom 0\n  padding-bottom 1em\n  font-size .8em\n  line-height 1.5\n\n.license\n  color color__text_second\n  a[rel=license]\n   vertical-align middle\n\n\n.intro\n  margin-bottom 1em\n  font-size font__size_small\n  color color__text_second\n\n.unpublished-post\n  color color__text_second\n\n.content\n  margin 2em 0 2em\n  line-height 1.5\n  position relative\n\n  img\n    box-shadow shadow__tiny\n\n\n.prevnext\n  margin 2em 0\n  position relative\n  clearfix()\n\n.prevnext__previous-arrow\n.prevnext__next-arrow\n  position absolute\n  font-size 1rem\n\n.prevnext__previous-arrow\n  left -1.5em\n\n.prevnext__next-arrow\n  right -1.5em\n\n.prevnext__previous\n.prevnext__next\n  width 40%\n  float left\n\n.prevnext__next\n  float right\n  text-align right\n\n.message\n  padding .5em 1em\n  box-shadow shadow__tiny\n  background img__noise color__blue\n  border color__blue_dark\n  &.info\n    background-color color__yellow\n    border color__yellow_dark\n  code\n    background-color rgba(255,255,255,.5);\n\n.sidenote\n  absolute left 100%\n  width 240px\n  margin-left 1.5em\n  padding 1em\n  font-size font__size_small\n  background-color #fff\n  box-shadow shadow__tiny\n  .num\n    color color__text_second\n\n.page-header__title a\n  margin 0\n  padding 0\n\n.page-header__rss-link\n  font-family \"IconicStroke\"\n  display block\n  absolute right 0\n  font-size 1.4em\n  color color__text\n  text-shadow none\n  margin 0\n  padding 0\n  &:visited\n   color color__text\n  &:hover\n    color color__text\n    text-decoration none\n\n\n.page-header__twitter-link\n  display block\n  size 20px\n  margin 0\n  padding 0\n  absolute right 2em\n  background url('/assets/img/twitter-icon.png')\n  background-size cover\n\n.page-header__title-link\n  color color__text\n  &:visited\n   color color__text\n  &:hover\n    color color__link\n\ncode\n  background-color #FFF\n  box-shadow shadow__tiny\n  font-size 15px\n\npre\n  padding 18px 18px\n  overflow scroll\n  background-color #fff\n  box-shadow shadow__tiny\n\ncode\n  font-family Consolas, Monaco, 'Andale Mono', monospace\n  padding 4px 4px 2px\n\npre > code\n  padding 0\n  background-color transparent\n  box-shadow none\n\n.prose\n  font-style italic\n  font-size 15px\n  margin 29px 0\n  display block\n\n.lazada-banner\n  display block\n  width 720px\n  height 120px\n  background url('/assets/img/lazada.jpg');\n  margin 0 0 2rem 0;\n  box-shadow shadow__tiny\n"
  },
  {
    "path": "assets/css/main.css",
    "content": "@font-face {\n  font-family: 'IconicStroke';\n  src: url(\"../iconic//iconic_stroke.eot\");\n  src: local('☺'), url(\"../iconic//iconic_stroke.ttf\") format('truetype'), url(\"../iconic//iconic_stroke.svg#iconic\") format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n/**\n * Variables\n */\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\nhtml,\nbody {\n  margin: 0;\n  height: 100%;\n}\nhtml {\n  font-family: Georgia, 'Times New Roman', serif;\n  font-size: 18px;\n}\nbody {\n  line-height: 1;\n  color: #000;\n  background: #fff;\n  background: url(\"/assets/img/noise.png\") #f4f4f4;\n  color: #404040;\n  text-shadow: 0 1px 0 rgba(255,255,255,0.5);\n}\nh1,\nh2,\nh3,\nh4,\nh5 {\n  font-weight: inherit;\n  font-style: inherit;\n  font-family: inherit;\n  font-size: 100%;\n  vertical-align: baseline;\n  margin: 0;\n  padding: 0;\n  border: 0;\n  outline: 0;\n  margin-bottom: 0.5em;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small {\n  font-size: 0.6em;\n  color: #888;\n}\nh1 {\n  font-size: 2em;\n}\nh2 {\n  font-size: 1.8em;\n}\nh3 {\n  font-size: 1.3em;\n}\nh4 {\n  font-size: 1.2em;\n}\nh5 {\n  font-size: 1em;\n  font-weight: bold;\n}\nul,\nol {\n  margin: 1em 0;\n}\na {\n  padding: 0.6em;\n  margin: -0.6em;\n  color: #06c;\n  text-decoration: none;\n}\na:hover {\n  text-decoration: underline;\n}\na:visited {\n  color: #506;\n}\na:visited.ignore-visited {\n  color: #06c;\n}\n.wrapper {\n  width: 720px;\n  margin: 0 auto;\n  padding: 4em 0 1em;\n  position: relative;\n  min-height: 100%;\n}\n.widget {\n  width: 728px;\n  height: 90px;\n  margin-bottom: 1em;\n  background-color: #fff;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n}\n.lwidget {\n  width: 160px;\n  height: 600px;\n  position: absolute;\n  left: 100%;\n  margin-left: 36px;\n}\n.money .money__wrapper {\n  width: 508px;\n  height: 105px;\n  margin: 0 auto;\n}\n.money {\n  margin-bottom: 1em;\n}\n.footer {\n  padding-bottom: 1em;\n  font-size: 0.8em;\n  line-height: 1.5;\n}\n.license {\n  color: #888;\n}\n.license a[rel=license] {\n  vertical-align: middle;\n}\n.intro {\n  margin-bottom: 1em;\n  font-size: 14px;\n  color: #888;\n}\n.unpublished-post {\n  color: #888;\n}\n.content {\n  margin: 2em 0 2em;\n  line-height: 1.5;\n  position: relative;\n}\n.content img {\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n}\n.prevnext {\n  margin: 2em 0;\n  position: relative;\n  zoom: 1;\n}\n.prevnext:before,\n.prevnext:after {\n  content: \"\";\n  display: table;\n}\n.prevnext:after {\n  clear: both;\n}\n.prevnext__previous-arrow,\n.prevnext__next-arrow {\n  position: absolute;\n  font-size: 1rem;\n}\n.prevnext__previous-arrow {\n  left: -1.5em;\n}\n.prevnext__next-arrow {\n  right: -1.5em;\n}\n.prevnext__previous,\n.prevnext__next {\n  width: 40%;\n  float: left;\n}\n.prevnext__next {\n  float: right;\n  text-align: right;\n}\n.message {\n  padding: 0.5em 1em;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  background: url(\"/assets/img/noise.png\") #b4d2f0;\n  border: 1px solid #99b3cc;\n}\n.message.info {\n  background-color: #f0e9b4;\n  border: 1px solid #ccc699;\n}\n.message code {\n  background-color: rgba(255,255,255,0.5);\n}\n.sidenote {\n  position: absolute;\n  left: 100%;\n  width: 240px;\n  margin-left: 1.5em;\n  padding: 1em;\n  font-size: 14px;\n  background-color: #fff;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n}\n.sidenote .num {\n  color: #888;\n}\n.page-header__title a {\n  margin: 0;\n  padding: 0;\n}\n.page-header__rss-link {\n  font-family: \"IconicStroke\";\n  display: block;\n  position: absolute;\n  right: 0;\n  font-size: 1.4em;\n  color: #404040;\n  text-shadow: none;\n  margin: 0;\n  padding: 0;\n}\n.page-header__rss-link:visited {\n  color: #404040;\n}\n.page-header__rss-link:hover {\n  color: #404040;\n  text-decoration: none;\n}\n.page-header__twitter-link {\n  display: block;\n  width: 20px;\n  height: 20px;\n  margin: 0;\n  padding: 0;\n  position: absolute;\n  right: 2em;\n  background: url(\"/assets/img/twitter-icon.png\");\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  background-size: cover;\n}\n.page-header__title-link {\n  color: #404040;\n}\n.page-header__title-link:visited {\n  color: #404040;\n}\n.page-header__title-link:hover {\n  color: #06c;\n}\ncode {\n  background-color: #fff;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  font-size: 15px;\n}\npre {\n  padding: 18px 18px;\n  overflow: scroll;\n  background-color: #fff;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n}\ncode {\n  font-family: Consolas, Monaco, 'Andale Mono', monospace;\n  padding: 4px 4px 2px;\n}\npre > code {\n  padding: 0;\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.prose {\n  font-style: italic;\n  font-size: 15px;\n  margin: 29px 0;\n  display: block;\n}\n.lazada-banner {\n  display: block;\n  width: 720px;\n  height: 120px;\n  background: url(\"/assets/img/lazada.jpg\");\n  margin: 0 0 2rem 0;\n  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n  box-shadow: 0 1px 1px rgba(0,0,0,0.15);\n}\n"
  },
  {
    "path": "assets/css/print.css",
    "content": "@media print {\n\t/* !Убираем украшения для страницы */\n\tbody {\n\t\tbackground: #FFF;\n\t\ttext-shadow: none;\n\t}\n\t\n\t/* !Переводим локальные ссылки в читаемый вид  */\n\ta::after {\n\t    content: \" (http://largescalejs.ru\" attr(href) \")\";\n\t}\n\t\n\t/* !Ссылки в заголовках делаем маленькими */\n\t.page-header__title-link::after {\n\t    font-size: 14px;\n\t}\n\t\n\t/* !Переводим все остальные ссылки в читаемый вид */\n\ta[href^=http]::after {\n\t    content: \" (\" attr(href) \")\";\n\t}\n\t\n\t/* !Используем всю ширину листа */\n\t.wrapper {\n\t\tmargin: 0;\n\t\tpadding: 0;\n\t\twidth: 100%;\n\t}\n\t\n\t/* !Чтобы после статьи не было много пустого места, уменьшаем отступ */\n\t.content {\n\t\tmargin-bottom: 1em;\n\t}\n\t\n\t/* !Убираем ненужные украшения для тегов в статьях, добавляем выделение */\n\tp > code {\n\t\t-webkit-box-shadow: none;\n\t\t-moz-box-shadow: none;\n\t\tbox-shadow: none;\n\t\tfont-weight: bold;\n\t}\n\t\n\t/* !Это нужно для того, чтобы код не был на двух страницах */\n\t.highlight > pre {\n\t\tpage-break-inside: avoid;\n\t}\n\t\n\t/* !Убираем абсолютное позиционирование для футера */\n\t.footer {\n\t\tposition: relative;\n\t\tpadding: 0;\n\t}\n\t\n\t/* !Прячем всё, что не несет смысловой нагрузки | !important для social-likes */\n\t.github__badge,\n\t.page-header > h4,\n\t.page-header__rss-link,\n\t.page-header__twitter-link,\n\t.social-likes,\n\t.widget,\n\t.money,\n\t#disqus_thread,\n\t.message,\n\t.license,\n\t.prevnext,\n\t.footer > p > span,\n\t.footer > p > a:last-child {\n\t\tdisplay: none !important;\n\t}\t\n}"
  },
  {
    "path": "assets/css/pygments.css",
    "content": ".highlight  { background: #ffffff; }\n.highlight .c { color: #999988; font-style: italic } /* Comment */\n.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */\n.highlight .k { font-weight: bold } /* Keyword */\n.highlight .o { font-weight: bold } /* Operator */\n.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */\n.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */\n.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #aa0000 } /* Generic.Error */\n.highlight .gh { color: #999999 } /* Generic.Heading */\n.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */\n.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #555555 } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #aaaaaa } /* Generic.Subheading */\n.highlight .gt { color: #aa0000 } /* Generic.Traceback */\n.highlight .kc { font-weight: bold } /* Keyword.Constant */\n.highlight .kd { font-weight: bold } /* Keyword.Declaration */\n.highlight .kp { font-weight: bold } /* Keyword.Pseudo */\n.highlight .kr { font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */\n.highlight .m { color: #009999 } /* Literal.Number */\n.highlight .s { color: #d14 } /* Literal.String */\n.highlight .na { color: #008080 } /* Name.Attribute */\n.highlight .nb { color: #0086B3 } /* Name.Builtin */\n.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */\n.highlight .no { color: #008080 } /* Name.Constant */\n.highlight .ni { color: #800080 } /* Name.Entity */\n.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */\n.highlight .nn { color: #555555 } /* Name.Namespace */\n.highlight .nt { color: #000080 } /* Name.Tag */\n.highlight .nv { color: #008080 } /* Name.Variable */\n.highlight .ow { font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mf { color: #009999 } /* Literal.Number.Float */\n.highlight .mh { color: #009999 } /* Literal.Number.Hex */\n.highlight .mi { color: #009999 } /* Literal.Number.Integer */\n.highlight .mo { color: #009999 } /* Literal.Number.Oct */\n.highlight .sb { color: #d14 } /* Literal.String.Backtick */\n.highlight .sc { color: #d14 } /* Literal.String.Char */\n.highlight .sd { color: #d14 } /* Literal.String.Doc */\n.highlight .s2 { color: #d14 } /* Literal.String.Double */\n.highlight .se { color: #d14 } /* Literal.String.Escape */\n.highlight .sh { color: #d14 } /* Literal.String.Heredoc */\n.highlight .si { color: #d14 } /* Literal.String.Interpol */\n.highlight .sx { color: #d14 } /* Literal.String.Other */\n.highlight .sr { color: #009926 } /* Literal.String.Regex */\n.highlight .s1 { color: #d14 } /* Literal.String.Single */\n.highlight .ss { color: #990073 } /* Literal.String.Symbol */\n.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */\n.highlight .vc { color: #008080 } /* Name.Variable.Class */\n.highlight .vg { color: #008080 } /* Name.Variable.Global */\n.highlight .vi { color: #008080 } /* Name.Variable.Instance */\n.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "assets/vendor/social-likes/social-likes.css",
    "content": "/*! Social Likes v3.0.1 by Artem Sapegin - http://sapegin.github.com/social-likes - Licensed MIT */\n.social-likes,.social-likes__widget{display:inline-block;padding:0;vertical-align:middle!important;word-spacing:0!important;text-indent:0!important;list-style:none!important}.social-likes{opacity:0}.social-likes_visible{opacity:1;-webkit-transition:opacity .1s ease-in;transition:opacity .1s ease-in}.social-likes>*{display:inline-block;visibility:hidden}.social-likes_vertical>*{display:block}.social-likes_visible .social-likes__widget{visibility:inherit}.social-likes__widget{display:inline-block;position:relative;white-space:nowrap}.social-likes__widget:before,.social-likes__widget:after{display:none!important}.social-likes_vertical .social-likes__widget{display:block;float:left;clear:left}.social-likes__button,.social-likes__icon,.social-likes__counter{text-decoration:none;text-rendering:optimizeLegibility}.social-likes__button,.social-likes__counter{display:inline-block;margin:0;outline:0}.social-likes__button{position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.social-likes__button:before{content:\"\";display:inline-block}.social-likes__icon{position:absolute;top:0;left:0}.social-likes__counter{display:none;position:relative}.social-likes_ready .social-likes__counter,.social-likes__counter_single{display:inline-block}.social-likes_ready .social-likes__counter_empty{display:none}.social-likes_vertical .social-likes__widget{display:block}.social-likes_notext .social-likes__button{padding-left:0}.social-likes_single-w{position:relative;display:inline-block}.social-likes_single{position:absolute;text-align:left;z-index:99999;visibility:hidden;opacity:0;-webkit-transition:visibility 0 .3s,opacity .3s ease-out;transition:visibility 0s .3s,opacity .3s ease-out;-webkit-backface-visibility:hidden;backface-visibility:hidden}.social-likes_single.social-likes_opened{visibility:visible;opacity:1;-webkit-transition:opacity .3s ease-out;transition:opacity .3s ease-out}.social-likes__button_single{position:relative}.social-likes,.social-likes__widget{border:0;font-size:14px}.social-likes__widget{line-height:20px}.social-likes{min-height:28px;margin:-3px}.social-likes,.social-likes_single-w{line-height:20px}.social-likes__widget{margin:3px}.social-likes__button,.social-likes__counter{font-family:\"Trebuchet MS\",\"Helvetica Neue\",Tahoma,sans-serif;font-size:14px;line-height:18px;border-width:1px;border-style:solid;border-radius:3px}.social-likes__button{padding:1px 4px 1px 20px;font-weight:700;text-shadow:0 1px 0 rgba(255,255,255,.6);box-shadow:0 1px 1px rgba(0,0,0,.05);-webkit-transition:border .1s ease-in-out,color .2s ease-in-out;transition:border .1s ease-in-out,color .2s ease-in-out}.social-likes__icon{width:20px;height:20px;background-repeat:no-repeat}.social-likes__counter{margin-left:7px;padding:1px 4px;font-weight:400;color:#666;color:rgba(0,0,0,.5);cursor:default}.social-likes__counter:before,.social-likes__counter:after{content:\"\";position:absolute;width:0;height:0}.social-likes__counter:before{top:4px;left:-6px;border:6px inset transparent;border-left:0;border-right:6px solid;border-right-color:inherit;opacity:.7}.social-likes__counter:after{top:5px;left:-4px;border:5px inset transparent;border-left:0;border-right:5px solid}.social-likes_vertical{margin:-6px -4px}.social-likes_vertical .social-likes__widget{margin:6px 4px}.social-likes_notext .social-likes__widget{margin:3px 2px}.social-likes_notext .social-likes__button{width:16px}.social-likes_single{margin-top:-16px;padding:6px 6px 4px;background:#fff;box-shadow:0 0 10px rgba(0,0,0,.25)}.social-likes__widget_single{margin:0}.social-likes__button_single{padding-left:19px;background:#e2e2e2;background:-webkit-linear-gradient(top,#f7f7f7,#e2e2e2);background:linear-gradient(top,#f7f7f7,#e2e2e2);color:#444;border-color:#ccc;border-color:rgba(179,179,179,.8);border-bottom-color:rgba(153,153,153,.8)}.social-likes__button_single:hover,.social-likes__widget_active .social-likes__button_single{background:#f4f4f4;background:-webkit-linear-gradient(top,#f0f0f0,#cfcfcf);background:linear-gradient(top,#f0f0f0,#cfcfcf);color:#222;border-color:#bbb;border-bottom-color:#9f9f9f}.social-likes__icon_single{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAABxVBMVEVyqHIsfCwneyc3iDctfi0sfiwAAABupm5pomlxp3FwqXB0q3RSllI0hTRAjEBXmVdJkklig2JspGx1qHVdnF2LrYv///9wrXBQllBvrW////9cnVxmiGZtpG11p3WNrY1fnV95sHkufi4xgjElYyUwiTAreSseTh4ugS4eUh4kZSQvfi8seiwwiDAxgzH///9tqW1mpmYggiC827wlhSXr9Os5jznk8OS62rqp0qk5lzk6mDoUhRQ0lTRwsXBfpV81izVkqGRYoVhoqWhfpF9Vo1VaoVppqWlgpWAwiTAyjDI6jzpBlEFkqmRtrG1bpltysHJFlkVZpVkkiCQ4jjgniScVexWSxZIxjTExhjEpiikyiDI0izQxiTEvii+m0KaNvo2FuoV+tn7c7NxIl0hurW6kzqSn0Kd5tXl7t3s4lDiEvoQziDMxiDFUpFRHm0f7/Pvi8OI6lTo9mD3i8eKy17JwsnB+u35NoU1JnUnT5tP8/fyn0ac8mDyq0qpPo09eql5AmkBDnENFnkVhrGE5mDnP5s8+mz4qjyq017QhiiHB38FHnkdJoElaqFrU6dQtkS2z1rOezJ7V6dXC38KfzZ/O5s44zy9hAAAAL3RSTlPu6ebu5uYA7u7w7u3w7e7w73TH2fGAAu3v7QPtfcjbhPHtyu1u5s1u7XZxzM7m7ed67K8AAADZSURBVAjXYxATFeZkYOfgYGfglJOXYhAUN3D3S0pMCLB3NpCUYRAy9PA11gcCYztHQ1kGETf/ZH1zS0tz/XBXFwUGHh8L/dJma+v68rwgJ34GLlN908a+yf0tTRX5gQIM3Pr6dR1T9PW7WxvKUiUY+FIqe2wn6ut3dlno6ysyMIcU1U6wmjrJ1qq6IF6agdc7q7im18amvUo/LUyDQdkhKltff1qbvn56aIweg1K0V0Rmib5+YUZwXI42g7pqpKeRiZmZiVFsrq4mA5uKGiMLKxMTKwujjhYbAFshM23jReW7AAAAAElFTkSuQmCC\");background-position:2px 3px}.social-likes__counter_single{background:#f6f6f6;border-color:#ddd}.social-likes__counter_single:after{border-right-color:#f6f6f6}.social-likes__button_facebook{padding-left:19px;background:#eceef5;background:-webkit-linear-gradient(top,#fff,#d8def4);background:linear-gradient(top,#fff,#d8def4);color:#3b5998;border-color:#cad4e7;border-color:rgba(202,212,231,.8);border-bottom-color:rgba(189,194,203,.8)}.social-likes__button_facebook:hover{background:#c0cdf3;background:-webkit-linear-gradient(top,#f2f3f7,#c0cdf3);background:linear-gradient(top,#f2f3f7,#c0cdf3);color:#253860;border-color:#b4bfd4;border-bottom-color:#b3b7bf}.social-likes__icon_facebook{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOBAMAAADtZjDiAAAAFVBMVEU7WZj///9thLTr7vRheaxFYp5geKvYYUakAAAAL0lEQVQI12NwYAABFgZkkCwIoQ2hNJSC0YKCEIaxoDFWeTAdpKSkJKikCqeh9gAAtSUEXqOhTAgAAAAASUVORK5CYII=\");background-position:3px 3px}.social-likes__counter_facebook{background:#f2f3f7;border-color:#cad4e7}.social-likes__counter_facebook:after{border-right-color:#f2f3f7}.social-likes__button_twitter{padding-left:19px;background:#d5e6ef;background:-webkit-linear-gradient(top,#fff,#d5e6ef);background:linear-gradient(top,#fff,#d5e6ef);color:#186487;border-color:#a4cce5;border-color:rgba(164,204,229,.8);border-bottom-color:rgba(158,186,204,.8)}.social-likes__button_twitter:hover{background:#bfdfed;background:-webkit-linear-gradient(top,#f2f8fc,#bfdfed);background:linear-gradient(top,#f2f8fc,#bfdfed);color:#0b3752;border-color:#9cbbcf;border-bottom-color:#68a0c4}.social-likes__icon_twitter{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAALCAMAAAB4W0xQAAAA3lBMVEUAAAD///8lseQltOvl9fr///////////8Af68Af5+Ay+gAf7QZmMglrd9Pwe0Ag7UBiL0ChLgMqOW03u8FgbAVnc96x+QlncoAfK8AgbP///8MrOrV7/hoxukAfa2N1fEjsOZBvOua1u4Afa+44/P///+HzOZsyetsy+4AgLBsxOgAiLy/5PEAfKwCg7YRiLQKmM+LyuIAhbkArO4Aq+0Aq+wAlc4AqOgAp+cAntoAjMIAqekAod4Am9cAmNIAo+EApuYApeUApOMApeQAjsQAod8AkckAqusAnNgAouBS5YTcAAAAM3RSTlMASPPzoXckDBAQwTCf8+ef8NH7pLPRueBgnzz7x9lw1/Hry4CuMIjf35/f78Fg4Wf5ar/hKdysAAAAhElEQVQIHR3BhQKCMBQF0KsCG3a3Yne/bYTd+v8/5PAcwEaIt/tL2DZQrELLPV7BbrUGKkGNI6HO9+dnswXKvspmkgdBwutZQOl68U9Hj4hudQCFvJCuK4lECprVatDfPo7QqCNJE9EIQsNBVxKJmAGNT+fq+yaZNhg0Zi5m44nTNBm0H8LlEYm9SraOAAAAAElFTkSuQmCC\");background-position:3px 5px}.social-likes__counter_twitter{background:#f2f8fc;border-color:#a4cce5}.social-likes__counter_twitter:after{border-right-color:#f2f8fc}.social-likes__button_plusone{padding-left:12px;background:#e4e4e4;background:-webkit-linear-gradient(top,#f5f5f5,#e4e4e4);background:linear-gradient(top,#f5f5f5,#e4e4e4);color:#da573b;border-color:#bbb;border-color:rgba(204,204,204,.8);border-bottom-color:rgba(179,179,179,.8)}.social-likes__button_plusone:hover{background:#f4f4f4;background:-webkit-linear-gradient(top,#f9f9f9,#f0f0f0);background:linear-gradient(top,#f9f9f9,#f0f0f0);color:#cd4427;border-color:#ddd;border-bottom-color:#ccc}.social-likes__icon_plusone{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAPCAMAAADqIa48AAAA1VBMVEUAAAD29vbeaU/w6uj6+vrs5uXijXvv7+/aVzvaVzr77eru6urutKfdZUvggm7aWT3linf8/PzfeGLp5eTnoJHmqp3hiHXhd2DxysLx6ef02NL39PTcalHcYUbcYUXaWTz219HccVnl1tP33dfkraHfbVPo4+LnlILt6encaE/cYkfkzsr57OrbWz/gfGbsq53fiXbmu7LgkH7q4d/48fDcdFzssqXqp5jl2dbcZ03j09DecVjebVXdclv4+PjdemTw8PD44dzik4LcmozjgWvgdFzxxLrCp/DQAAAACHRSTlMA////////+EuuwZEAAAB3SURBVAgdLcEFFoIAEEDBDwLu2t3d3d19/yOJD2dIpjMJcTk+SikrHpJwwIJKEYhJBGjjykk0COMekBexQeeALVlAj0tolQvAS/eL2aCJ63L/nHSK5/bWSQfPRrXeAJ7XtdOtan8Ij5VlGDVTz+DnZ2Tqgb+t7r4MkwpuQ8fKEQAAAABJRU5ErkJggg==\");background-position:0 6px}.social-likes__counter_plusone{background:#f9f9f9;border-color:#d2d2d2}.social-likes__counter_plusone:after{border-right-color:#f9f9f9}.social-likes__button_mailru{padding-left:18px;background:#004584;background:-webkit-linear-gradient(top,#5d90ba,#004584);background:linear-gradient(top,#5d90ba,#004584);color:#fff;color:rgba(255,255,255,.95);border-color:#1e65a5;border-color:rgba(11,84,153,.8);border-bottom-color:rgba(3,27,48,.8);text-shadow:0 -1px 0 rgba(0,0,0,.3)}.social-likes__button_mailru:hover{background:#001e5d;background:-webkit-linear-gradient(top,#618cae,#001e5d);background:linear-gradient(top,#618cae,#001e5d);color:#fff;color:rgba(255,255,255,.99);border-color:#094984;border-bottom-color:#031b30}.social-likes__icon_mailru{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABhlBMVEUAAAD0xQD/xgBcSwAAAAD8ywC1kQD7yQC5lAD/1AAAAABsVwD/zAD6yAD5yAD/xgAAAAAAAAAAAAAQDgAoIAAAAABFLgC/mQD/yADcsQAAAAAsIwAAAAAAAAD4xwAAAAA7MAD6yQBbSQDZrQDcsgDywQDxwAClggD/yADnuAAAAAD8zAD7ygDargD8zAAzKQATEAD8ywBHOQBAMgAtJAD7ygD6yQCMcACLbwAPDACigQCphwBiUAC3kgDZrgAAAADIogAAAAAAAAD/zABmTwAAAAAGBgBZSADrvACBaAAAAADTqgD8ygDcsgD5yQD8ywD8ywDywQDqvQDRqQDpvADktwCyjgAAAAA8MADouQCzkADuvgDuwADEnQD2xQD9ywD7yQAAAADougDbsgBYRAC/mQCgfwDZrgDnvgDGoACYegChgAA+MADIogAAAADsvgDtvgDzwgB4XgCqiAD6yADHnwDNpQBpUwClhADmuQB8YwDzwwCHawCffQD0wwDktwDAnAD9ywDU1CnPAAAAgXRSTlMA+AmjBdjG/WcMZKke7PkSCGkCiV4DC8kq4wtWEA7pUXPgltnm9fJKIUxTeNnYaZVPz5JHdvewt25mwcVifdtuxCZhLS2HcaLfqYGT4W72wO2m4tyl0r9HmLSY8m/UmpniCrZdNNFWqDdnkF8lXiDtve1GZ/5uWJi8SaT2a0Oro2IKDPtyAAAAy0lEQVQIHQXBA0NDYQCG0Wf87h2zrWXXss1l215tme8/7xwAgAAAAOBsbJHkqbMBoLpeDT3R3gEdjgKES6tc3V39fT7/QzAA7JuyiEfSQfz18wecob2xYHnTuOtRf28mzKWud01JAfcfsr70zp1uLnYKgSdZ33rmXFfbxgZOZL0owa1jq62y0yanSNZv8hS3VzWty4op23EcOjuC5oqO+YnJ6c1ir8nNADLbVzS3Oru0mJ+emgKQN+JfX1uYGspyAwAMb/hmBmvTAP4BUaQsfohkhJwAAAAASUVORK5CYII=\");background-position:1px 2px}.social-likes__counter_mailru{background:#fff1c2;border-color:#ffc70d}.social-likes__counter_mailru:after{border-right-color:#fff1c2}.social-likes_notext .social-likes__icon_mailru{background-position:2px 2px}.social-likes__button_vkontakte{background:#436f96;background:-webkit-linear-gradient(top,#8faecf,#436f96);background:linear-gradient(top,#8faecf,#436f96);color:#fff;color:rgba(255,255,255,.95);border-color:#4d84c1;border-color:rgba(78,131,193,.8);border-bottom-color:rgba(52,88,127,.8);text-shadow:0 -1px 0 rgba(0,0,0,.3)}.social-likes__button_vkontakte:hover{background:#4e80ab;background:-webkit-linear-gradient(top,#a2c0df,#4e80ab);background:linear-gradient(top,#a2c0df,#4e80ab);color:#fff;color:rgba(255,255,255,.99);border-color:#5788be;border-bottom-color:#3b6798}.social-likes__icon_vkontakte{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1BMVEUeRmv6+/weRGn09vicrb0cRGsAAADu8fS9x9IgQWrg5usgRGsfQ2ocQmcqVX8cOHEiRG4AP38dQW0iRWghQ2scRWgfRGsdRmv29/keR2vW3eUkSG0fRmn6+vsbRG5wiJ8hRmySpLcAf39eeZSruMfe4+pNaokAAAAXRXOYqrodR2yRpLedrr4fP2qQo7UfRWqer7/n6u78/f3o7PAzM2aNoLTEz9l4jqbz9fbN1d21wc8/X4AkTHFyiaJ0jKMcRnGywM0fRWseRGsxV3kgRWqDma4eRGogRWodRGofRWxRbouHmq4eQ2zt8PPW3eUfQ2tEY4W2ws5cd5J5j6eltcRogJxNbIqUprhwhaCvvMtMa4qEma3Gz9k6Wn9aeJIfRGr////flzUiAAAAYHRSTlNM/Uv4uy0A89Uf60dIGwYJHgQjFiYsYUX5MuUVQfslfTakAmnA6FkBC6w9o7oYnzC57v7vBZnagfff0X1ho60SzIB0Q2e0ZT5WSTV1RPLQQFq+Qn6qXYGbVJ45aswwV0ob93UPAAAAtUlEQVQY02NgE5SWFGdiAANuBV4+NgZ1XnkpiQQIYFTVExFk4FdjTkAAI3N7BmHtBGTgIMQgYACk2R09xNxsDYEsDlEGThaQCLdXpLe7HUiEFSriGZHg5+OKLMIdGxwQ54sswhMVEu4fxowkEh+akBDNY4msJigm0NnGGCKiAxJxYhJzsTaD2K6rCXI+FxeXBdiFViIMGsqMyG42FWZQElJEeExWRd+EgY1PQAsaGAwMMnL8bAARvTwsqGgkuAAAAABJRU5ErkJggg==\");background-position:1px 2px}.social-likes__counter_vkontakte{background:#eaeef3;border-color:#afc1d4}.social-likes__counter_vkontakte:after{border-right-color:#eaeef3}.social-likes__button_odnoklassniki{padding-left:17px;background:#f6900b;background:-webkit-linear-gradient(top,#f6bb6d,#f6900b);background:linear-gradient(top,#f6bb6d,#f6900b);color:#fff;color:rgba(255,255,255,.95);border-color:#d99c27;border-color:rgba(217,154,38,.8);border-bottom-color:rgba(197,137,7,.8);text-shadow:0 -1px 0 rgba(0,0,0,.12)}.social-likes__button_odnoklassniki:hover{background:#f69a21;background:-webkit-linear-gradient(top,#fbcc5a,#f69a21);background:linear-gradient(top,#fbcc5a,#f69a21);color:#fff;color:rgba(255,255,255,.99);border-color:#f0b22c;border-bottom-color:#c59121}.social-likes__icon_odnoklassniki{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAPCAMAAAABFhU/AAAAt1BMVEUAAAD9/f37+/sAAAAAAABYWFgAAAD19fUAAAD///8AAAD////z8/P9/f3///////9ycnK/v7/////9/f37+/v19fV3d3fa2tr////////BwcHh4eGlpaXHx8f///+srKz////5+fn4+Pj///94eHj5+fltbW35+fns7Oz19fX9/f3////q6ur9/f3S0tL////8/Pynp6fl5eX////9/f2bm5v9/f3s7Oz////////s7OwAAAD///+3C/ewAAAAPHRSTlMA5e0eBCsj0QIDHQ/J6F0SKGhR9/DUQA4h/GsRJXMnKPZWU/MzrDGvr5+j0q2gf8nyUjzw8Urusqt1RBmYPbn7AAAAd0lEQVQIHQXBBQKCQABFwYcgu4DSdnd367//uZwBgvyTBwDJSdIuAQ4qX6W2wF2X30MFcNaVrwpgr9v7qTWQGkkmhWC6zI7ZfBIQa7baLMaK6dckSWaEF3YlDVwP2o46qg8hctRoGtUjWhVT9aq1Sg/ruxYb+vYPq3IOiMcZvH4AAAAASUVORK5CYII=\");background-position:4px 3px}.social-likes__counter_odnoklassniki{background:#ffe9be;border-color:#d9ab53}.social-likes__counter_odnoklassniki:after{border-right-color:#ffe9be}.social-likes_notext .social-likes__icon_odnoklassniki{background-position:5px 3px}.social-likes__button_pinterest{padding-left:20px;background:#eee;background:-webkit-linear-gradient(top,#fefefe,#d3d3d3);background:linear-gradient(top,#fefefe,#d3d3d3);color:#c71a28;border-color:#bbb;border-color:rgba(186,186,186,.8);border-bottom-color:rgba(153,153,153,.8)}.social-likes__button_pinterest:hover{background:#efefef;background:-webkit-linear-gradient(top,#fff,#d9d9d9);background:linear-gradient(top,#fff,#d9d9d9);color:#c11524;border-color:rgba(186,186,186,.6);border-bottom-color:rgba(153,153,153,.6)}.social-likes__icon_pinterest{background-image:url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAARCAMAAADjcdz2AAABYlBMVEUAAADBByTBAB62ACTBByS5ABe/ABXBBiPBBiTBByO/AB/ABiS/AAC0AB7BBiPBBiO+BCDBByTBBSMAAADBBiPBBCPBBiTBBiTBByTBBiPABiO+ByK8BSG/BCLBByO/AyPABiLBBSPBByTAByPABSPABiPABCPBBiO/AyPBBSPAByTBBiLBBiTBBiLABiSqAADBBiTBByPCACTABiTBByTBBSPBBiO9BSDABSTBBiTBBiTBByTABiPBBSPBAyPABiTBBiPBByTABSTBByS/BCS7ABrBBiPBBiTAByO5ACLBByPBBySyABnBBiPABiLABSJ/AADBBiPAByTBBiPBBiTBByTBBSPBBiS/BSLBByTCByO/Bh/ABiTDByTCByTABiS/BiTBBiOZAAC/BCLBByTBBSTABiTBBSS6AB3AByTBBiTBByTBByS4ABy/AB/AByTBBiTBBSPCByXCCCXCByTDCCV4snBOAAAAcnRSTlMA7BkH6wsM6rylEOYEEZbPN42zAew6/ZnGo5dDLjSjQCXXooJeeznLSKtF2/RLTQbs1RXerdlPL1qhqrGcMkdveemwkWkTp/qPFoGqCtOUsALR5sTr2bL8LOSyKM2qxclUnQU81tiTWxrN29T7Egji39pl2aR6AAAA3ElEQVQYGQXBA4IDUAxAwdet7XZt27Zt22aSf/+dAQAAAACAqdVk8HBvOwUAeNMrYiZqhYQfwDthameh88sT50IBIG36+3IPnB6LTMJIwZ5ev4p/R1cXLIvmWXCfD/F3+xHZX1uakzG25JpnyX8fOFlkXIfIyR0fb5ARnaVoHnKywc1jNhJUHWVQe+lz0c3b4O60SmdJbEA6SIjNr+8wLNJEo0qYKlWTGWLd7VRGRWug3Kmm+jOtzQ0e1TDgD2mwp0tMTVxpBCBQn8y2iYnTsjgAUFvS4vPVVVcA/AMRETlXnYR1ZQAAAABJRU5ErkJggg==\");background-position:2px 1px}.social-likes__counter_pinterest{background:#fff5f6;border-color:#f0a8ae}.social-likes__counter_pinterest:after{border-right-color:#fff5f6}"
  },
  {
    "path": "atom.xml",
    "content": "---\nlayout: nil\ntitle : Atom Feed\n---\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\">\n \n  <title>{{ site.author }} - {{ site.title }}</title>\n  <link href=\"{{ site.production_url }}/atom.xml\" rel=\"self\"/>\n  <link href=\"{{ site.production_url }}\"/>\n  <updated>{{ site.time | date_to_xmlschema }}</updated>\n  <id>{{ site.production_url }}</id>\n  <author>\n    <name>{{ site.author }} «{{ site.title }}»</name>\n    <email>anton_shuvalov@me.com</email>\n  </author>\n\n  {% for post in site.posts %}\n    {% if post.published %}\n      <entry>\n        <title>{{ post.title }}</title>\n        <updated>{{ post.date | date_to_xmlschema }}</updated>\n        {% if post.extlink %}\n          <link href=\"{{ post.external_link }}\"/>\n        {% else %}\n          <id>{{ site.production_url }}{{ post.id }}</id>\n          <link href=\"{{ site.production_url }}{{ post.url }}\"/>\n          <content type=\"html\">{{ post.content | xml_escape }}</content>\n        {% endif %}\n      </entry>\n    {% endif %}\n  {% endfor %}\n</feed>\n"
  },
  {
    "path": "epub/_source.md",
    "content": "% Паттерны для масштабируемых JavaScript-приложений\n% Эдди Османи\n\n## Вступление\n\nВ этой книге мы обсудим набор паттернов, который поможет вам в создании \nбольших масштабируемых JavaScript-приложений. Материал книги основан на моем\nодноименном докладе, впервые прочитанном на конференции «LondonJS», и\nвдохновленном [предшествующей ему работой][01] Николаса Закаса.\n\n### Кто я и почему я решил об этом написать?\n\nМеня зовут Эдди Османи. Сейчас я работаю JavaScript- и UI-разработчиком в AOL.\nЯ занимаюсь планированием и написанием фронтенд-архитектуры для следующего\nпоколения наших пользовательских приложений. Эти приложения весьма сложны. Они\nнуждаются в архитектуре, позволяющей, с одной стороны легко их масштабировать,\nа с другой достаточно легко использовать повторно их модули. Также я занимаюсь\nразработкой шаблонов, которые можно применять в разработке приложений подобного\nмасштаба настолько качественно, насколько это вообще возможно.\n\nКроме того, я рассматриваю себя как евангелиста шаблонов проектирования (хотя\nесть много экспертов, разбирающихся в этом лучше меня). В прошлом я написал книгу \n«[Essential JavaScript Design Patterns][02]», а сейчас я занимаюсь написанием более \nподробного продолжения этой книги.\n\n\n### Могу ли я уместить эту книгу в 140 символов?\n\nЯ уместил эту статью в один твит, на случай, если у вас совсем мало времени:\n\nМеньше связанности: используйте паттерны «модуль», «фасад» и «медиатор». Модули\nобщаются через медиатор, а фасад обеспечивает безопасность.\n\n\n[01]: http://yuilibrary.com/theater/nicholas-zakas/zakas-architecture/\n[02]: http://addyosmani.com/resources/essentialjsdesignpatterns/book/\n\n## Что из себя представляет «большое» JavaScript приложение? \n\nПеред тем как я начну, давайте постараемся определить, что именно мы имеем \nв виду, когда говорим о больших JavaScript-приложениях. Этот вопрос\nя считаю своего рода вызовом опытным разработчикам, и ответы на него,\nсоответственно, получаются очень субъективными.\n\nРади эксперимента я предложил нескольким среднестатистическим разработчикам\nдать собственное определение этому термину. Один из разработчиков сказал, что\nречь идет о «JavaScript-приложениях, состоящих из более чем 100 000 \nстрок кода», когда другой определил что большое приложение «содержит больше\nчем 1 МБ JavaScript». Я расстроил храбрецов — оба этих варианта\nдалеки от истины. Количество кода не всегда коррелирует со сложностью приложения.\n100 000 строк легко могут оказаться самым ничем не примечательным простым кодом.\n\nЯ не знаю, подходит ли мое собственное определение к любому случаю, но я верю,\nчто оно находится ближе всего к тому, что действительно представляет из себя\nбольшое JavaScript-приложение.\n\nЯ думаю, что большие JavaScript-приложения решают нетривиальные задачи,\nа поддержка таких приложений требует от разработчика серьезных усилий.\nПри этом, большая часть работы по манипуляции данными и их отображению ложится\nна браузер.\n\nЯ думаю, что последняя часть определения — самая важная.\n\n## Давайте обсудим вашу существующую архитектуру \n\n\nРаботая над большим JavaScript-приложением, не забывайте уделять **достаточное\nколичество времени** на планирование изначальной архитектуры, к которой такие \nприложения очень чувствительны. Большие приложения обычно представляют\nиз себя очень сложные системы, гораздо более сложные, чем вы представляете\nсебе изначально.\n\nЯ должен подчеркнуть значение этой разницы — я видел разработчиков, которые,\nсталкиваясь с большими приложениями, делали шаг назад и говорили: «Хорошо,\nу меня есть несколько идей, которые хорошо показали себя в моем предыдущем\nпроекте среднего масштаба. Думаю, они точно сработают и для чего-то большего,\nне так ли?». Конечно, до какого-то момента это может быть так, но, пожалуйста,\nне принимайте это как должное — по большей части большие приложения имеют ряд\nдостаточно серьезных проблем, с которыми нужно считаться. Ниже я приведу\nнесколько доводов в пользу того, почему вам стоит уделить немного больше времени \nпланированию архитектуры своего приложения, и чем вам это будет полезно\nв долгосрочной перспективе.\n\nБольшинство JavaScript-разработчиков в архитектуре своих приложений обычно\nиспользует различные комбинации следующих компонентов:\n\n*   виджеты\n*   модели\n*   представления\n*   контроллеры\n*   шаблоны\n*   библиотеки\n*   ядро приложения.\n\n**Ссылки по теме:**  \n[Ребекка Мёрфи — Создание архитектуры JavaScript-приложений][2-1]  \n[Питер Мишо — MVC архитектура для JavaScript-приложений][2-2]  \n[StackOverflow — Дискуссия о современных MVC-фреймворках][2-3]  \n[Дуг Найнер — Поддерживаемые плагины и фабрика виджетов][2-4]  \n\n\nВероятно, вы выносите различные функции ваших приложений в отдельные модули,\nлибо используете какие-нибудь другие шаблоны проектирования для подобного\nразделения. Это очень хорошо, но здесь есть ряд потенциальных проблем,\nс которыми вы можете столкнуться при таком подходе.\n\n\n### 1. Готова ли ваша архитектура к повторному использованию кода уже сейчас?\n\nМогут ли отдельные модули использоваться самостоятельно? Достаточно ли они\nавтономны для этого? Мог бы я прямо сейчас взять один из модулей вашего большого \nприложения, просто поместить его на новую веб-страницу, а затем, тут же, начать\nего использовать? У вас может возникнуть вопрос: «Действительно ли это так\nнеобходимо?», но, как бы то ни было, я надеюсь, что вы думаете о будущем. Что, \nесли ваша компания начнет создавать все больше и больше нетривиальных\nприложений, которые будут иметь некоторую общую функциональность? Если кто-то\nскажет: «Нашим пользователям очень нравится использовать модуль чата в нашем\nemail-клиенте, почему бы нам не добавить этот модуль к нашему новому приложению для\nсовместной работы с документами?», будет ли это возможно, если мы не уделим\nдолжного внимания контролю кода?\n\n\n### 2. Сколько модулей в вашей системе зависит от других модулей?\n\nНасколько сильно связаны ваши модули? Перед тем, как я погружусь в объяснения\nо том, как важна слабая связанность модулей, я должен отметить, что не всегда есть\nвозможность создавать модули, не имеющие абсолютно никаких зависимостей\nв системе. К примеру, одни модули могут расширять функции других, уже существующих.\nЭта тема, скорее всего, относится к группировке модулей на основе некоторой\nфункциональности. Отдельные наборы модулей должны работать в вашем приложении без\nбольшого количества зависимостей, чтобы наличие или загрузка других модулей\nне влияла на их работоспособность.\n\n\n### 3. Сможет ли ваше приложение работать дальше, если его отдельная часть сломается?\n\nЕсли вы разрабатываете приложения, подобные Gmail, и ваш webmail-модуль (или \nгруппа модулей) перестанет работать из-за ошибки, то это не должно заблокировать\nпользовательский интерфейс или помешать пользователям использовать другие части\nвашего приложения, к примеру, такие как чат. В то же время, как было сказано\nраньше, было бы идеально, если бы модули могли работать и за пределами вашей\nархитектуры. В моей лекции я упоминал динамические зависимости — возможность\nзагружать модули, исходя из определенных действий пользователя. К примеру,\nребята из Gmail могли бы изначально держать чат закрытым, не загружая его\nкод при открытии страницы. А в тот момент, когда пользователь решит\nвоспользоваться им — соответствующий модуль будет динамически загружен и\nвыполнен. В идеальном случае хотелось бы выполнить это без каких-то негативных\nэффектов в вашем приложении.\n\n\n### 4. Насколько легко вы сможете тестировать отдельные модули?\n\nКогда вы работаете над масштабными системами, есть вероятность, что\nразличные части этой системы будут использовать миллионы пользователей.\nВполне вероятно, что эти части будут использоваться не только в предусмотренных\nвами ситуациях. В конечном счете, код может использоваться повторно в огромном\nколичестве различных окружений, и важно, чтобы модули были достаточно\nпротестированы. Тестировать модули необходимо и внутри архитектуры, для которой\nон был изначально разработан, и снаружи. По моему мнению, это дает наибольшую\nгарантию того, что модуль не сломается при попадании в другую систему.\n\n[2-1]: http://rmurphey.com/blog/2010/08/27/code-org-take-2-structuring-javascript-applications/\n[2-2]: http://michaux.ca/articles/mvc-architecture-for-javascript-applications\n[2-3]: http://stackoverflow.com/questions/5112899/knockout-js-vs-backbone-js-vs\n[2-4]: http://msdn.microsoft.com/en-us/scriptjunkie/ff706600\n\n## Думай о будущем \n\nВ процессе создания архитектуры большого приложения, очень важно думать о будущем.\nНе только о том, что будет через месяц или через год, но и о том, что будет после\nэтого. Что может измениться? Конечно, невозможно достаточно точно предсказать\nкак ваше приложение будет развиваться, но, вне всякого сомнения, имеет смысл\nподумать об этом. Думаю, что найдется, хотя бы один специфичный аспект вашего\nприложения, о котором стоит поразмыслить.\n\nРазработчики зачастую слишком сильно связывают манипуляцию с DOM-элементами и\nостальные части приложения, даже если до этого они не поленились разделить\nбизнес-логику на модули. Подумайте, почему в долгосрочной перспективе это\nможет быть плохой идеей?\n\nОдин из слушателей моей лекции предположил, что такая архитектура негибка, и может\nне работать в будущем. Это действительно так, но есть другая проблема, игнорирование\nкоторой окажет еще более негативный эффект.\n\nВ будущем, вы можете принять решение о **замене** Dojo, jQuery, Zepto или YUI на\nчто-нибудь совершенно иное. Причиной такого перехода может быть производительность,\nбезопасность или дизайн. Это может стать серьезной проблемой, потому как библиотеки\nне предусматривают простой замены. Цена замены библиотеки будет высокой, если ваше\nприложение тесно с ней связано.\n\nЕсли вы используете Dojo (как многие слушатели на моей лекции), вы можете\nбыть уверены, что нет ничего лучше, на что имело бы смысл сейчас перейти. Но\nможете ли вы быть уверены, что в течении двух-трех лет не появится что-нибудь,\nчто вызовет у вас интерес? Что-нибудь, на что вы можете решить перейти.\n\nТакое решение может быть достаточно простым для небольших проектов, но **не для\nбольших приложений**, архитектура которых, в целом, достаточна их поддержки.\n\nТакое решение может быть достаточно простым для небольших проектов, но на **больших\nприложениях** с непродуманной архитектурой всю тяжесть смены библиотеки вы ощутите\nсразу.\n\nПодводя итог, взгляните на вашу архитектуру сейчас. Сможете ли вы сегодня сменить\nвашу библиотеку на любую другую, не переписывая при этом ваше приложение\nполностью? Если это не так, то вам стоит продолжить чтение. Я думаю, что\nв архитектуре, которую мы обсуждаем, вы найдёте кое-что интересное. \n\nНекоторые из известных JavaScript-разработчиков раньше уже излагали проблемы,\nо которых я написал выше. Вот три ключевых цитаты, которыми я бы хотел поделиться\nс вами.\n\n«Секрет создания больших приложений в том, чтобы никогда не создавать больших\nприложений. Разбейте ваши приложения на маленькие части, а затем собирайте из\nэтих маленьких тестируемых фрагментов ваше большое приложение»\n**Джастин Майер, автор «JavaScriptMVC»**\n\n«Секрет в том, чтобы признаться самому себе с самого начала, что вы понятия\nне имеете о том, как ваше приложение будет развиваться. Когда вы согласитесь\nс этим, вы начнете проектировать систему основываясь на защите. Вы определите\nключевые области, в которых, вероятнее всего будут происходить изменения. Очень\nчасто это не составляет труда, если потратить на это немного времени. К примеру,\nвы ожидаете, что любая часть приложения, которая взаимодействует с другой\nсистемой — это потенциальная мишень для изменений. И вы понимаете, что здесь вам\nпонадобится абстракция».  \n**Николас Закас, автор книги «Высокопроизводительный JavaScript**\n\nИ последняя, но тоже очень важная цитата:\n\n«Чем сильнее компоненты связаны между собой, тем меньше возможностей для их\nповторного использования, тем сложнее вносить изменения, не получая при этом различных\nпобочных эффектов в самых неожиданных местах»\n**Ребекка Мёрфи, автор книги «Фундаментальные основы jQuery»**\n\nЭти принципы необходимы для создания архитектуры, способной выдержать испытание\nвременем. Важно всегда помнить о них.\n\n\n## Мозговой штурм \n\nДавайте немного подумаем, что мы хотим получить.\n\nМы хотим получить слабосвязанную архитектуру с функциональностью, разделенную\nна **независимые модули**, которые, в идеале, не должны иметь зависимостей друг\nот друга. Когда случается что-то интересное, модули **сообщают** об этом другим\nчастям приложения, а промежуточный слой интерпретирует их сообщения и необходимым\nобразом реагирует на них.\n\nДля примера, у нас есть JavaScript-приложение, отвечающее за онлайн-пекарню. Одно из\nинтересных нам сообщений может быть таким: «Партия из 42 батонов готова к доставке».\n\nМы используем отдельный слой для обработки сообщений модулей, чтобы а) модули\nне взаимодействовали напрямую с ядром, б) модули не взаимодействовали напрямую\nдруг с другом. Это помогает не допустить падения приложения из-за различных\nошибок внутри одного из модулей. Также это позволяет нам перезапускать модули\nесли они вдруг перестали работать из-за какой-нибудь ошибки.\n\nЕще один момент — безопасность. На самом деле, немногие из нас заботятся\nо внутренней безопасности своих приложений в должной мере. Когда мы определяем\nструктуру приложения, мы говорим себе, что мы достаточно умны для того, чтобы\nпонимать что в нашем коде должно быть публичным, а что приватным.\n\nХорошо, но поможет ли это если вы решите определить что именно разрешено\nмодулю выполнять в системе? К примеру, в моем приложении, ограничив доступ из\nмодуля веб-чата к интерфейсу модуля администрирования, я смогу уменьшить шансы\nна успешное использование XSS уязвимостей, которые я не смог найти в виджете.\nМодули не должны иметь доступ ко всему. Вероятно, в вашей существующей\nархитектуре они могут использовать любые части системы, но уверены ли вы, что\nэто действительно необходимо?\n\nПромежуточный слой, проверяющий имеет ли модуль доступ к определенной части\nвашего фреймворка, обеспечивает большую безопасность вашей системы. Фактически,\nэто значит что модули могут взаимодействовать только с теми компонентами \nсистемы, с которыми мы разрешим им взаимодействовать.\n\n\n### Архитектура, которую я предлагаю вам\n\nАрхитектура, о которой мы говорим, представляет из себя комбинацию трех\nизвестных шаблонов проектирования: модуль, фасад и медиатор.\n\nВ отличии от традиционной модели, в которой модули напрямую взаимодействуют друг с\nдругом, в этой слабосвязанной архитектуре модули всего лишь публикуют события (в\nидеале, не зная о других модулях в системе). Медиатор используется для подписки на\nсообщения от модулей и для решения, каким должен быть ответ на уведомление. Паттерн\nфасад используется для ограничения действий разрешенных модулям.\n\nВ следующих главах я более детально расскажу о каждом из этих шаблонов\nпроектирования.\n\n## Теория модулей \n\nВероятно, в каком-то виде вы уже используете модули в своей существующей\nархитектуре. Если это не так, то в этой главе я покажу вам, как они устроены.\n\nМодули — это **целая** часть любой хорошей архитектуры приложения. Обычно\nмодули выполняют одну определенную задачу в более крупных системах и могут быть\nвзаимозаменяемы.\n\nВ некоторых реализациях модули могут иметь свои собственные зависимости, которые\nбудут загружены автоматически, собирая вместе таким образом все компоненты\nсистемы. Такой подход считается более масштабируемым, в отличие от ручной\nзагрузки модулей или подстановки тега `script`.\n\nКаждое нетривиальное приложение должно создаваться из модульных компонентов.\nРассмотрим GMail: вы можете рассматривать модули, как независимые единицы\nфункциональности, которые могут и должны существовать сами по себе; возьмём к\nпримеру чат. Скорее всего он основан на своём отдельном модуле чата, но так как\nэтот модуль скорее всего очень сложный, то он вероятно состоит из более мелких\nвспомогательных модулей. Например, один из таких модулей мог бы отвечать за\nиспользование смайликов и он же мог бы использоваться не только в чате, но также\nи в почте.\n\nВ рассматриваемой архитектуре модули имеют **очень ограниченные знания** о том, что\nпроисходит в других частях системы. Вместо этого мы делегируем ответственность\nмедиатору и фасаду.\n\nВ этом и заключается идея нашей архитектуры — если модуль заботится исключительно\nо том, чтобы уведомить систему об интересующих ее происшествиях, и не волнуется\nзапущены ли другие модули, то система может добавлять, удалять или заменять одни\nмодули, не ломая при этом другие, что было бы невозможно при сильной связанности.\n\nСлабая связанность — необходимое условие для того, чтобы такая идея была возможна.\nОна делает поддержку модулей проще, удаляя зависимости в коде там, где это возможно.\nВ вашем случае, одни модули должны работать корректно в не зависимости от того в\nкаком порядке загрузились другие модули. Когда слабая связанность реализована\nэффективно, становится очевидно, как изменения в одной части системы влияют на другие ее части.\n\nВ JavaScript есть несколько мнений о том, как могут быть реализованы модули, включая\nшаблон «Модуль» и Object Literal (литеральная запись объекта `var obj = {};`).\nОпытные разработчики должно быть уже знакомы с ними. Если это так, то вы можете\nпропустите следующую главу и  перейти сразу к главе «CommonJS Modules».\n\n## Паттерн «Модуль» \n\n«Модуль» — это популярная реализация паттерна, инкапсулирующего приватную\nинформацию, состояние и структуру, используя замыкания. Это позволяет оборачивать\nпубличные и приватные методы и переменные в модули, и предотвращать их\nпопадание в глобальный контекст, где они могут конфликтовать с интерфейсами\nдругих разработчиков. Паттерн «модуль» возвращает только публичную часть API,\nоставляя всё остальное доступным только внутри замыканий.\n\nЭто хорошее решение для того, чтобы скрыть внутреннюю логику от посторонних глаз и\nпроизводить всю тяжелую работу исключительно через интерфейс, который вы определите\nдля использования в других частях вашего приложения. Этот паттерн очень похож на\nнемедленно-вызываемые функции ([IIFE][6-3]), за тем исключением, что модуль вместо\nфункции, возвращает объект.\n\nВажно заметить, что в JavaScript нет настоящей приватности. В отличии от некоторых\nтрадиционных языков, он не имеет модификаторов доступа. Переменные технически\nне могут быть объявлены как публичные или приватные, и нам приходится использовать\nобласть видимости для того, чтобы эмулировать эту концепцию. Благодаря замыканию,\nобъявленные внутри модуля переменные и методы доступны только изнутри этого модуля.\nПеременные и методы, объявленные внутри объекта, возвращаемого модулем, будут\nдоступны всем.\n\nНиже вы можете увидеть корзину покупок, реализованную с помощью паттерна «модуль».\nПолучившийся компонент находится в глобальном объекте `basketModule`, и содержит\nвсё, что ему необходимо. Находящийся внутри него, массив `basket` приватный,\nи другие части вашего приложения не могут напрямую взаимодействовать с ним. \nМассив `basket` существует внутри замыкания, созданного модулем, и\nвзаимодействовать с ним могут только методы, находящиеся в том же контексте\n(например, `addItem()`, `getItem()`). \n\n\n```\nvar basketModule = (function() {\n  var basket = []; // приватная переменная\n    return { // методы доступные извне\n        addItem: function(values) {\n            basket.push(values);\n        },\n        getItemCount: function() {\n            return basket.length;\n        },\n        getTotal: function() {\n           var q = this.getItemCount(),p=0;\n            while(q--){\n                p+= basket[q].price; \n            }\n            return p;\n        }\n    }\n}());\n```\n\nВнутри модуля, как вы заметили, мы возвращаем объект. Этот объект автоматически\nприсваивается переменной `basketModule`, так что с ним можно взаимодействовать\nследующим образом:\n\n```\n// basketModule - это объект со свойствами, которые могут также быть и методами:\nbasketModule.addItem({item:'bread', price:0.5});\nbasketModule.addItem({item:'butter', price:0.3});\n\nconsole.log(basketModule.getItemCount());\nconsole.log(basketModule.getTotal());\n\n// А следующий ниже код работать не будет:\nconsole.log(basketModule.basket); // undefined потому что не входит в возвращаемый объект\nconsole.log(basket); // массив доступен только из замыкания\n```\n\n\nМетоды выше, фактически, помещены в неймспейс `basketModule`.\n\nИсторически, паттерн «модуль» был разработан в 2003 году группой людей, в число\nкоторых входил [Ричард Корнфорд][6-4]. Позднее, этот паттерн был популяризован\nДугласом Крокфордом в его лекциях, и открыт заново в блоге YUI благодаря Эрику \nМирагилиа.\n\nДавайте посмотрим на реализацию «модуля» в различных библиотеках и фреймворках.\n\n**Dojo** \n\nDojo старается обеспечивать поведение похожее на классы с помощью `dojo.declare`,\nкоторый, кроме создания «модулей», также используется и для других вещей.\nДавайте попробуем, для примера, определить `basket` как модуль внутри неймспейса\n`store`:\n\n```\n// традиционный способ\nvar store = window.store || {};\nstore.basket = store.basket || {};\n\n// с помощью dojo.setObject\ndojo.setObject(\"store.basket.object\", (function() {\n    var basket = [];\n    function privateMethod() {\n        console.log(basket);\n    }\n    return {\n        publicMethod: function() {\n            privateMethod();\n        }\n    };\n}()));\n```\n\nЛучшего результата можно добиться, используя `dojo.provide` и миксины.\n\n\n**YUI** \n\nСледующий код, по большей части, основан на примере реализации паттерна\n«модуль» в фреймворке YUI, разработанным Эриком Миргалиа, но более\nсамодокументирован.\n\n```\nYAHOO.store.basket = function () {\n\n    // приватная переменная:\n    var myPrivateVar = \"Ко мне можно получить доступ только из YAHOO.store.basket.\";\n    \n    // приватный метод:\n    var myPrivateMethod = function() {\n        YAHOO.log(\"Я доступен только при вызове из YAHOO.store.basket\");\n    }\n    \n    return {\n        myPublicProperty: \"Я - публичное свойство\",\n        myPublicMethod: function() {\n            YAHOO.log(\"Я - публичный метод\");\n    \n            // Будучи внутри корзины я могу получить доступ к приватным переменный и методам:\n            YAHOO.log(myPrivateVar);\n            YAHOO.log(myPrivateMethod());\n    \n            // Родной контекст метода myPublicMethod сохранён\n            // поэтому мы имеет доступ к this\n            YAHOO.log(this.myPublicProperty);\n        }\n    };\n    \n}();\n\n```\n\n\n**jQuery** \n\nСуществует множество способов, чтобы представить jQuery-код в виде паттерна «модуль», \nдаже если этот код не напоминает привычные jQuery-плагины. Бен Черри ранее \nпредлагал способ, при котором, если у модулей есть общие черты, то они объявляются \nчерез функцию-обертку.\n\nВ следующем примере функция `library` используется для объявления новой\nбиблиотеки и, автоматически, при создании библиотеки (т.е. модуля),\nсвязывает вызов метода `init` с `document.ready`.\n\n```\nfunction library(module) {\n  $(function() {\n    if (module.init) {\n      module.init();\n    }\n  });\n  return module;\n}\n\nvar myLibrary = library(function() {\n   return {\n     init: function() {\n       /* код модуля */\n     }\n   };\n}());\n```\n\n**Ссылки по теме:**  \n[Бен Черри — Погружение в паттерн «Модуль»][6-5]  \n[Джон Ханн — Будущее — это модули, а не фреймворки][6-6]  \n[Натан Смит — Ссылки на window и document в модулях (gist)][6-7]  \n\n\n[6-3]: http://benalman.com/news/2010/11/immediately-invoked-function-expression/\n[6-4]: http://groups.google.com/group/comp.lang.javascript/msg/9f58bd11bd67d937\n[6-5]: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth\n[6-6]: http://lanyrd.com/2011/jsconf/sfgdk/\n[6-7]: https://gist.github.com/274388\n\n## Литеральная нотация объекта \n\nВ литеральной нотации объект описывается внутри блока фигурных скобок (`{}`), \nкак набор разделенных запятой пар ключ/значение. Ключи объекта могут\nбыть как строками, так и идентификаторами. После имени ставится двоеточие.\nВ объекте не должно стоять запятой после последней пары ключ/значение,\nтак как это может привести к ошибкам.\n\nЛитерал объекта не требует использования оператора `new` для создания экземпляра,\nно он не должен стоять в начале выражения, так как открытая `{` может быть\nвоспринята как начало блока. Ниже вы можете увидеть пример модуля, определенного\nс помощью литеральной нотации объекта. Новые члены объекта могут быть добавлены\nс помощью конструкции `myModule.property = 'someValue';`\n\n\nПаттерн «модуль» может быть полезен для многих вещей. Но если вы считаете, что вам\nне нужно делать приватными некоторые методы или свойства, то литерал объекта — \nболее чем подходящий выбор.\n\n```\nvar myModule = {\n    myProperty: 'someValue',\n    // Литералы объектов могут содержать свойства и методы.\n    // ниже в свойстве определен другой объект,\n    // для описания конфигурации:\n    myConfig: {\n        useCaching: true,\n        language: 'en'\n    },\n    // Очень простой метод\n    myMethod: function() {\n        console.log('I can haz functionality?');\n    },\n    // вывод значения заданного в конфигурации\n    myMethod2: function() {\n        console.log('Caching is: ' + ((this.myConfig.useCaching) ? 'enabled' : 'disabled'));\n    },\n    // переопределение конфигурации\n    myMethod3: function(newConfig) {\n        if (typeof newConfig == 'object') {\n            this.myConfig = newConfig;\n            console.log(this.myConfig.language); \n        }\n    }\n};\n\nmyModule.myMethod();  // 'I can haz functionality'\nmyModule.myMethod2(); // Вывод 'enabled'\nmyModule.myMethod3({language:'fr',useCaching:false}); // 'fr'\n```\n\n**Ссылки по теме:**  \n[Ребекка Мёрфи — Использование объектов для организации вашего кода][7-1]  \n[Стоян Стефанов — 3 способа определения класса в JavaScript ][7-2]  \n[Бен Алман — Разъяснения по литералам объектов (понятия JSON-объект не существует)][7-3]  \n[Джон Резиг - Простое наследование в JavaScript][7-4]\n\n[7-1]: http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code\n[7-2]: http://www.phpied.com/3-ways-to-define-a-javascript-class/\n[7-3]: http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/\n[7-4]: http://ejohn.org/blog/simple-javascript-inheritance/\n\n## CommonJS Модули \n\n\nВозможно, вы что-то слышали о [CommonJS][8-4] за последние пару лет. CommonJS — это\nдобровольная рабочая группа, которая проектирует, прототипирует и стандартизирует\nразличные JavaScript API. На сегодняшний день они ратифицировали стандарты для\nмодулей и пакетов — CommonJS определяют простой API для написания модулей,\nкоторые могут быть использованы в браузере с помощью тега `<script>`, как \nс синхронной, так и с асинхронной загрузкой. Реализация паттерна «модуль»\nс помощью CommonJS выглядит очень просто, и я нахожу это уверенным шагом на пути\nк модульной системе, предложенной в ES Harmony (следующей версии JavaScript).\n\nВ структурном плане, CommonJS-модуль представляет собой готовый к переиспользованию\nфрагмент JavaScript-кода, который экспортирует специальные объекты, доступные\nдля использования в любом зависимом коде. CommonJS все чаще используется как\nстандартный формат JavaScript-модулей. Существует большое количество хороших\nуроков по написанию CommonJS-модулей, но обычно они описывают две главных идеи: \nобъект `exports`, содержащий то, что модуль хочет сделать доступным для других\nчастей системы, и функцию `require`, которая используется одними модулями для\nимпорта объекта `exports` из других.\n\n```\n/*\nПример обеспечения совместимости между AMD и обычным CommonJS с помощью\nсоздания обертки над последним:\n*/\n\n(function(define) {\ndefine(function(require,exports) {\n  // module contents\n  var dep1 = require(\"dep1\");\n  exports.someExportedFunction = function() {...};\n  //...\n});\n})(typeof define==\"function\"?define:function(factory){factory(require,exports)});\n```\n\nЕсть много хороших JavaScript-библиотек, для загрузки модулей в формате\n**CommonJS**, но моим личным предпочтением является RequireJS. Полный учебник\nпо RequireJS выходит за рамки этого руководства, но я могу порекомендовать вам\nпочитать [пост Джеймса Брука «ScriptJunkie»][8-5]. Кроме того, я знаю многих людей,\nкоторые предпочитают Yabble.\n\nИз коробки, RequireJS уже содержит методы для простого создания статичных\nмодулей с обертками. Благодаря этим методам становится действительно легко\nсоздавать модули с поддержкой асинхронной загрузки. RequireJS может легко\nзагружать модули и их зависимости, выполняя тело модуля, сразу, как только это\nстановится возможным.\n\nНекоторые разработчики утверждают, что CommonJS-модули не достаточно удобны\nдля применения в браузере, потому как без определенной помощи со стороны сервера,\nих нельзя загрузить с помощью тега `script`. Давайте представим, что есть некая\nбиблиотека для кодирования изображений в виде ASCII-изображений, которая\nэкспортирует функцию `encodeToASCII`. Модуль использующий эту библиотеку\nбудет выглядеть примерно так:\n\n```\nvar encodeToASCII = require(\"encoder\").encodeToASCII;\nexports.encodeSomeSource = function() {\n  // Обработка изображения, затем вызов encodeToASCII\n}\n```\n\nЭтот код не будет работать с тегом `script`. Ему необходим определенный контекст.\nЯ имею в виду наш метод `encodeToASCII`, который ссылается на несуществующие\nв контексте `window` методы `require` и `exports`. В такой ситуации нам пришлось\nбы писать `require` и `exports` для каждого отдельного модуля. Эту проблему\nлегко решают клиентские библиотеки, которые загружают скрипты через XHR-запросы,\nа затем выполняют `eval()`.\n\nПопробуем переписать этот модуль, используя RequireJS:\n\n```\ndefine(function(require, exports, module) {\n  var encodeToASCII = require(\"encoder\").encodeToASCII;\n  exports.encodeSomeSource = function() {\n    // Обработка изображения, затем вызов encodeToASCII\n  }\n});\n```\n\nДля разработчиков, которые хотят пойти дальше простого использования JavaScript\nв своих проектах, CommonJS модули — прекрасная возможность начать движение в эту\nсторону, но придется потратить немного времени и познакомиться поближе с этим\nформатом. Все, что я рассказал — это только верхушка айсберга. К счастью, \nCommonJS wiki и SitePen содержат много материалов, которые помогут вам глубже\nразобраться в устройстве CommonJS-модулей.\n\n**Ссылки по теме:**  \n[Спецификации CommonJS-модулей][8-1]  \n[Алекс Янг - Прояснение CommonJS-модулей][8-2]  \n[Заметки о CommonJS- и RequireJS-модулях][8-3]  \n\n[8-1]: http://wiki.commonjs.org/wiki/Modules\n[8-2]: http://dailyjs.com/2010/10/18/modules/\n[8-3]: http://requirejs.org/docs/commonjs.html#packages\n[8-4]: http://commonjs.org\n[8-5]: http://msdn.microsoft.com/en-us/scriptjunkie/ff943568\n\n## Паттерн «Фасад» \n\nКлючевую роль в архитектуре, которую мы обсуждаем в этой книге, играет\nшаблон проектирования под названием «фасад».\n\nКак правило, фасад используется для создания некоторой абстракции,\nскрывающей за собой совершенно иную реальность. Паттерн «фасад»\nобеспечивает удобный **высокоуровневый интерфейс** для больших блоков\nкода, скрывая за собой их истинную сложность. Относитесь к фасаду, как\nк упрощенному API, который вы отдаете в пользование другим разработчикам.\n\nФасад — **структурный паттерн**. Часто его можно обнаружить\nв JavaScript-библиотеках и фреймворках, где пользователям доступнен\nтолько фасад — ограниченная абстракция широкого диапазона поведений\nреализованных внутри.\n\nБлагодаря такому подходу, пользователь взаимодействует только с интерфейсом, \nне имея никакого представления о подсистемах, которые скрываются за ним.\n\nПричина, по которой нам интересен фасад — возможность скрыть детали реализации \nконкретной функциональности, хранящиеся в модулях. Это позволит нам вносить изменения\nв реализацию, не сообщая об этом пользователям.\n\nНадежный фасад — наш упрощенный интерфейс — позволит нам не беспокоиться о тесных\nсвязях некоторых модулей нашей системы с dojo, jQuery, YUI, zepto или какой-либо\nдругой библиотекой. Это становится не так важно. Вы можете переходить с одной\nбиблиотеки на другую не меняя слой взаимодействия. К примеру, с jQuery на dojo.\nБолее того, у вас появляется возможность совершить такой переход на более поздних\nэтапах, без изменений в остальных частях системы.\n\nНиже я написал достаточно простой пример использования фасада. Как вы видите,\nу нашего модуля есть несколько приватных методов. Чтобы создать более простой\nинтерфейс для доступа к этим методам мы используем фасад.\n\n```\nvar module = (function() {\n  var _private = {\n    i: 5,\n    get: function() {\n      console.log('Текущее значение:' + this.i);\n    },\n    set: function(val) {\n      this.i = val;\n    },\n    run: function() {\n      console.log('процесс запущен');\n    },\n    jump: function() {\n      console.log('резкое изменение');\n    }\n  };\n  return {\n    facade: function(args) {\n      _private.set(args.val);\n      _private.get();\n      if (args.run) {\n        _private.run();\n      }\n    }\n  }\n}());\n\nmodule.facade({run:true, val:10}); // Текущее значение: 10, процесс запущен\n```\n\n\nЭто и есть та причина, по которой мы добавили фасад к нашей архитектуре.\nВ следующей главе мы обсудим медиатор. Принципиальное различие между\nэтими двумя паттернами заключается в том, что фасад, как структурный паттерн,\nвсего лишь передает существующую функциональность в медиатор, в то время как\nмедиатор, как поведенческий паттерн, может эту функциональность расширять.\n\n**Ссылки по теме:**  \n[Дастин Диас, Росс Хармс — «Профессиональные шаблоны проектирования JavaScript» (Глава 10, доступно для чтения в Google Books)][9-1]  \n\n[9-1]: http://books.google.co.uk/books?id=za3vlnlWxb0C&lpg=PA141&ots=MD5BLTsSzH&dq=javascript%20facade%20pattern&pg=PA141#v=onepage&q=javascript facade pattern&f=false\n\n## Паттерн «Медиатор» \n\nОбъяснить, что представляет собой паттерн «медиатор» достаточно просто на примере\nследующей аналогии — представьте себе контроль траффика в аэропорте: все решения\nо том, какие самолеты могут взлетать или садиться, принимает диспетчер. Для этого,\nвсе сообщения, исходящие от самолетов, поступают в башню управления, вместо того,\nчтобы пересылаться между самолетами напрямую. Такой централизованный контроллер —\nэто и есть ключ к успеху нашей системы. Это и есть «медиатор».\n\n\nМедиатор применяется в системах, где взаимодействие между модулями может быть\nвесьма сложными, но, в то же время, **хорошо определенным**. Если вы полагаете,\nчто связи между модулями вашей системы будут постоянно расти и усложняться, то, \nвозможно, вам стоит добавить центральный элемент управления. Паттерн «медиатор»\nотлично подходит для этой роли.\n\nМедиатор выступает в качестве посредника в общении между различными модулями,\n**инкапсулируя их взаимодействие**. Кроме того, этот шаблон проектирования,\nпредотвращая прямое взаимодействие различных компонентов системы, способствует\nослаблению связей в коде. В нашей системе он так же помогает в решении проблем,\nсвязанных с зависимостями модулей.\n\nКакие еще преимущества существуют у «медиатора»? К примеру, медиатор позволяет\nкаждому модулю функционировать абсолютно независимо от других компонентов системы,\nчто приводит к большей гибкости. Если вам ранее уже приходилось использовать\nпаттерн «наблюдатель» в роли системы доставки событий между различными частями\nв вашей системе, то вам не составит труда разобраться с медиатором.\n\nДавайте посмотрим на модель взаимодействия модулей и медиатора:\n\n![][10-7]\n\nМы можем рассматривать модули, как «издателей», публикующих события. Медиатор же\nявляется и «издателем» и «подписчиком» одновременно. В примере, `Module 1` посылает\nсообщение, предполагающее некоторую реакцию, медиатору. Затем, медиатор, получив\nсообщение, уведомляет другие модули об определенных действиях, которые необходимо\nвыполнить для завершения задачи. `Module 2` выполняет необходимые `Module 1`\nдействия, и сообщает о результате обратно, в медиатор. В это же время, медиатор\nзапускает `Module 3` для логгирования поступающих сообщений.\n\nОбратите внимание: здесь нет прямого взаимодействия между модулями. Если\nв `Module 3` произойдет ошибка или, к примеру, он просто перестанет работать,\nто медиатор, теоретически, может приостановить выполнение задач в других модулях,\nзатем перезапустить `Module 3` и продолжить работу, практически не влияя на работу\nвсей системы. Такая слабая связанность модулей является одним из самых сильных\nпреимуществ паттерна «медиатор», который я вам предлагаю использовать.\n\nПосмотрим на его преимущества:\n\nУменьшает связывание модулей, добавляя посредника — центральный элемент управления.\nЭто позволяет модулям отправлять и слушать сообщения, не затрагивая остальной\nчасти системы. Сообщения могут быть обработаны любым количеством модулей сразу.\n\n\nБлагодаря слабой связанности кода, внедрение новой функциональности \nпроисходит существенно легче.\n\n\nИ недостатки:\n\nМодули больше не могут взаимодействовать напрямую. Использование медиатора\nприводит к небольшому падению производительности — такова природа слабой\nсвязанности — становится достаточно трудно определить реакцию системы,\nотталкиваясь только от событий, происходящих в ней. \n\nНаконец, системы с высокой связанностью кода являются обычно источником\nвсевозможных проблем, решением которых может стать уменьшение связанности.\n\n\n**Пример:** одна из возможных реализаций паттерна «медиатор», основанная на работе\n[@rpflorence][10-8]\n\n```\nvar mediator = (function() {\n    var subscribe = function(channel, fn) {\n        if (!mediator.channels[channel]) mediator.channels[channel] = [];\n        mediator.channels[channel].push({ context: this, callback: fn });\n        return this;\n    },\n \n    publish = function(channel) {\n        if (!mediator.channels[channel]) return false;\n        var args = Array.prototype.slice.call(arguments, 1);\n        for (var i = 0, l = mediator.channels[channel].length; i < l; i++) {\n            var subscription = mediator.channels[channel][i];\n            subscription.callback.apply(subscription.context, args);\n        }\n        return this;\n    };\n \n    return {\n        channels: {},\n        publish: publish,\n        subscribe: subscribe,\n        installTo: function(obj) {\n            obj.subscribe = subscribe;\n            obj.publish = publish;\n        }\n    };\n\n}());\n```\n\n\nИ два примера использования реализации, написанной выше:\n\n```\n//Pub/sub on a centralized mediator\n\nmediator.name = \"tim\";\nmediator.subscribe('nameChange', function(arg) {\n    console.log(this.name);\n    this.name = arg;\n    console.log(this.name);\n});\n\nmediator.publish('nameChange', 'david'); //tim, david\n\n\n//Pub/sub via third party mediator\n\nvar obj = {name: 'sam'};\nmediator.installTo(obj);\nobj.subscribe('nameChange', function(arg) {\n    console.log(this.name);\n    this.name = arg;\n    console.log(this.name);\n});\n\nobj.publish('nameChange', 'john'); //sam, john\n```\n\n**Ссылки по теме:**  \nStoyan Stefanov — Page 168, JavaScript Patterns  \n[HB Stone — Шаблоны проектирования JavaScript: Медиатор][10-1]  \n[NVince Huston — Шаблон Медиатора (не относится JavaScript, но кратко)][10-2]  \n\n\n[10-1]: http://arguments.callee.info/2009/05/18/javascript-design-patterns--mediator/\n[10-2]: http://www.vincehuston.org/dp/mediator.html\n\n[10-7]: ../assets/img/chart4a.jpg\n[10-8]: https://github.com/rpflorence\n\n## Использование фасада: абстракция ядра \n\n\nФасад, в нашей архитектуре, выполняет роль **абстракции** ядра приложения. Фасад\nнаходится между медиатором и модулями. Модули в идеальной ситуации должны\nвзаимодействовать **исключительно** с фасадом и не должны знать абсолютно ничего\nо других компонентах нашей системы.\n\nФасад также обеспечивает **последовательный и доступный в любой момент интерфейс**\nдля модулей. Это похоже на **песочницу** в архитектуре Николаса Закаса.\n\nВсе сообщения от модулей, адресованные медиатору, проходят через фасад, поэтому\nон должен быть весьма надежен. Его роль в этом взаимодействии — анализ\nсообщений, исходящих от модулей, и передача этих сообщений в медиатор.\n\nВ дополнение к предоставлению интерфейса, фасад также выступает в роли защиты,\nопределяя с какими частями системы может взаимодейстовать модуль. Модули\nмогут вызывать только **свои собственные** методы. Для доступа к другим\nкомпонентам системы модулям необходимо иметь специальное разрешение.\n\nК примеру, модуль может отправить сообщение `dataValidationCompletedWriteToDB`.\nВ подобных случаях задача фасада — убедиться, действительно ли этот модуль\nимеет права на запись в базу данных. Таким образом, мы пытаемся предотвратить\nпроблемы с модулями, которые пытаются делать то, что они не должны. \n\nПодведем итоги: медиатор представляет собой интерпретацию паттерна «подписчик/издатель», \nно он получает только те сообщения, которые нас действительно интересуют. За\nфильтрацию же всех сообщений отвечает фасад.\n\n## Использование медиатора: ядро приложения \n\nВ этой главе мы кратко пройдемся по некоторым зонам ответственности\nмедиатора, который играет роль ядра приложения. Но, для начала,\nдавайте разберемся, что он представляет собой в целом. \n\nОсновная задача ядра — управлять **жизненным циклом** модулей. Когда ядро \nполучает **интересное сообщение** от модулей, оно должно определить, как\nприложение должно на это отреагировать, таким образом ядро определяет момент\n**запуска** или **остановки** определенного модуля или набора модулей.\n\n\nВ идеальной ситуации, однажды запущенный модуль, должен функционировать\nсамостоятельно. В задачи ядра не входит принятие решений о том, как реагировать,\nнапример, на событие `DOM ready` — в нашей архитектуре у модулей есть достаточно\nвозможностей для того, чтобы принимать такие решения самостоятельно.\n\nВозможно, у вас вызовет удивление то обстоятельство, что модулям может\nпотребоваться остановка. Такое может произойти случае, если модуль вышел из строя,\nлибо если в работе модуля происходят серьезные ошибки. Решение об остановке\nмодуля может помочь предотвратить некорректную работу его методов.\nПоследующий перезапуск таких модулей должен помочь решить возникшие проблемы.\nЦель здесь в минимизации негативных последствий для пользователя нашего приложения.\n\nВ дополнение, ядро должно быть в состоянии **добавлять или удалять** модули\nне ломая ничего. Типичный пример — определенный набор функций может быть\nнедоступен на начальном этапе загрузки страницы, но эти функции могут быть\nзагружены динамически, на основе определенных действий со стороны пользователя.\nВозвращаясь к нашему примеру с GMail, google может, по умолчанию, держать чат\nв свернутом состоянии и загружать соответствующий ему модуль динамически,\nтолько в том случае, если пользователь проявит интерес к использованию этой\nчасти приложения. С точки зрения оптимизации производительности, это должно\nдать заметный эффект.\n\nОбслуживание ошибок должно также обрабатываться ядром приложения. В добавок\nк сообщению об интересных событиях модули также должны сообщать и о любых ошибках\nкоторые произошли в их работе. Ядро должно соответствующим образом реагировать\nна эти ошибки (к примеру, останавливать модули, перезапускать их и тд). Это\nважно, как часть слабо связанной архитектуры, позволяющей реализовать новый\nили лучший подход к реализации уведомления пользователя об ошибках без ручного\nизменения в каждом модуле. Используя механизм для публикации событий и подписки\nна них в медиаторе мы сможем достичь этого.\n\n## Собираем всех вместе \n\n*   **Модули** содержат специфичные части функциональности вашего приложения.\n    Они публикуют уведомления, информирующие приложение о том, что случилось\n    что-то интересное. Это их главная забота. Как я поясню в FAQ, модули\n    могут зависеть от различных вспомогательных методов для работы с DOM, но\n    идеальным бы было отсутствие любых зависимостей от других компонентов\n    системы. Модули не должны иметь отношение к тому:\n\n    *   какие объекты или модули подписаны на их сообщения,\n    *   где находятся эти объекты (на клиенте или на сервере),\n    *   какое количество объектов подписано на уведомления.\n\n**![][13-9]**\n\n*   **Фасад** — абстракция ядра защищающая его от прямого контакта\n    с модулями. Он подписывается на интересные сообщения от модулей, и говорит:\n    «Отлично! Что случилось? Расскажи мне больше подробностей!». Так же фасад\n    поддерживает безопасность модулей, проверяя, действительно ли модуль,\n    отправивший сообщение, имеет необходимые права для того, чтобы его сообщение\n    было соответствующим образом обработано ядром.\n\n**![][13-10]**\n\n*   **Медиатор (ядро приложения)** выступает в роли управляющего публикациями\n    событий и подписками на них. Он отвечает за управление запуском и остановку\n    модулей по необходимости. Здесь используется частичная динамическая загрузка\n    зависимостей, и гарантия того, что упавшие модули могут быть централизованно\n    перезапущены в случае проблем.\n\n**![][13-11]**\n\nИтог этой архитектуры в том, что модули, в большинстве случаев, практически \nне зависят от других компонентов приложения. Они могут быть легко тестируемы\nи легко поддерживаемы в рамках своего кода. Кроме того, благодаря низкому уровню\nсвязанности кода, такие модули можно легко скопировать на новую страницу для\nиспользования в другом проекте, не прилагая дополнительных усилий. Так же, эти\nмодули могут быть загружены или удалены динамически в процессе работы приложения.\n\n\n[13-9]: ../assets/img/chart1a.gif\n[13-10]: ../assets/img/chart2a.gif\n[13-11]: ../assets/img/chart3a.gif\n\n## Развитие идей медиатора: автоматическая регистрация событий \n\nКак раньше упоминал Михаэль Махемофф, размышляя о больших и масштабируемых \nJavaScript-приложениях, весьма выгодно использовать в приложении больше динамических\nсвойств языка. Вы можете прочитать об этом больше в его заметках на странице\n[Google+][14-12], но я хочу подробнее остановиться на одной особенности —\nавтоматической регистрации событий (AER).\n\nAER решает проблему связывания подписчиков и издателей путем добавления паттерна,\nкоторый автоматически вызывает нужные методы на основе соглашения об именовании.\nДля примера, если модуль публикует сообщение `messageUpdate`, произойдет\nавтоматический вызов одноименного метода у всех модулей, которые такой имеют.\n\nИспользование этого паттерна подразумевает регистрацию всех компонентов,\nкоторые могут подписываться на события, регистрацию всех событий на которые\nможно подписаться и, наконец, для каждого метода подписки в вашем наборе\nкомпонентов должно быть событие. Это выглядит очень интересно по отношению\nк нашей архитектуре, но так же имеет ряд интересных проблем.\n\nК примеру, при работе динамически, объекты должны регистрировать себя после\nсоздания. Если вас это заинтересовало — посмотрите [пост][14-13] Михаэля об AER,\nгде он более подробно обсуждает как бороться с проблемами этого подхода.\n\n[14-12]: https://plus.google.com/106413090159067280619/posts/hDZkVrDXZR6\n[14-13]: http://softwareas.com/automagic-event-registration\n\n## Frequently Asked Questions \n\n### Возможно ли обойтись без использования фасада (песочницы)?\n\nХотя архитектура, которую я изложил здесь, использует фасад для обеспечения\nбезопасности, вполне возможно достичь того же с помощью медиатора — сообщения\nмогут обрабатываться непосредственно ядром без использования фасада. Такая\nупрощенная версия все равно будет обеспечивать необходимо низкий уровень\nсвязывания кода, но при выборе этого варианта, нужно понимать, насколько вам\nбудет комфортно работать с модулями, которые взаимодействуют напрямую\nс ядром.\n\n### В книге говорилось о том, что модули не должны иметь любых зависимостей, касается ли это библиотек (к примеру, jQuery)\n\nЯ специально вынес вопрос о зависимостях от других модулей сюда. Когда\nнекоторые разработчики выбирают подобную архитектуру, этот выбор подразумевает\nчто они будут использовать определенные абстракции от DOM-библиотек. К примеру,\nвы можете использовать вспомогательную утилиту, которая будет возвращать нужные\nвам DOM-элементы используя jQuery (или dojo). Благодаря этому, модули все еще могут\nудобно работать с DOM, но уже будут это делать не напрямую, жестко используя\nконкретную библиотеку. Существует достаточно много способов, как сделать\nмодули независимыми, но стоит понимать, что, в обсуждаемой нами архитектуре,\nидеальные модули не должны иметь зависимостей.\n\nВы заметите, что иногда при таком подходе становится гораздо легче взять\nзаконченный модуль из одного проекта и перенести его в другой проект с небольшими\nдополнительными усилиями. Должен сказать, я полностью согласен с тем, что\nпорой намного лучше, когда модули, вместо определенной части своей функциональности,\nпросто используют другие модули. Как бы то ни было, держите в голове то, что\nтакие модули, в некоторых случаях, могут потребовать гораздо больше усилий для\nпереноса в другой проект.\n\n### Я хочу сегодня же начать использовать эту архитектуру. Есть ли какой-то шаблон от которого я бы мог оттолкнуться?\n\nКогда у меня будет немного свободного времени, я планирую написать для этой\nкниги бесплатный шаблон проекта, но сейчас, наверное, лучший выбор — \nплатное учебное пособие написанное Эндрю Бэджис — [«Написание модульного JavaScript»][15-14]\n(разоблачу себя: деньги от этой реферальной ссылки, как и любые другие, полученные\nот этой книги деньги уже инвестируются в обзор будущих материалов перед тем, как я порекомендую их другим).\nПособие Эндрю включает в себя скринкаст и примеры кода. Оно охватывает большую\nчасть идей, которые мы обсуждали в книге, но в нем, вместо названия «фасад» \nиспользуется слово «песочница», как у Николаса Закаса. Так же, здесь есть\nобсуждение о том, что работа с DOM-библиотеками, в идеале, должна быть реализована\nпосредством абстракции. Я говорил об этом в предыдущем вопросе. Тут Эндрю\nделает ставку на некоторые интересные шаблоны, обобщающие работу с селекторами\nDOM, таким образом, в крайнем случае, замена библиотеки может быть выполнена\nв несколько коротких строк. Я не говорю, что это лучший или самый правильный\nподход, но я поступаю именно так.\n\n### Могут ли модули взаимодействовать с ядром напрямую, если это необходимо?\n\nКак заметил раньше Николас Закас, технически, нет никаких причин, мешающих\nмодулям напрямую обращаться к ядру. Это скорее относится к «лучшим практикам».\nЕсли вы намерены строго следовать этой архитектуре, то вы должны также следовать\nее правилам. Либо следовать правилам более простой архитектуры, которая была\nописана в первом вопросе.\n\n\n[15-14]: http://bit.ly/orGVOL\n\n## Credits \n\nСпасибо Николасу Закасу за его оригинальную работу в объединении большого\nколичества концепций существующих на сегодняшний день. Спасибо Андрэ Хэнссон\nза технический обзор книги и за отзывы, которые помогли сделать эту книгу лучше.\nСпасибо Ребекке Мюрфей, Джастину Майеру, Питеру Мишо, Полу Айришу и Алексу\nСекстону и всем, чьи материалы относятся к теме обсуждаемой в книге и являлись\nисточником вдохновения как для меня так и для других.\n"
  },
  {
    "path": "epub/largescale-js.fb2",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FictionBook xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\" xmlns:l=\"http://www.w3.org/1999/xlink\"><description><title-info><book-title>Паттерны для масштабируемых JavaScript-приложений</book-title><author><first-name>Эдди</first-name><last-name>Османи</last-name></author></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p>Паттерны для масштабируемых JavaScript-приложений</p></title><annotation><p>Эдди Османи</p><p></p></annotation><section><section><title><p>Вступление</p></title><section><p>В этой книге мы обсудим набор паттернов, который поможет вам в создании больших масштабируемых JavaScript-приложений. Материал книги основан на моем одноименном докладе, впервые прочитанном на конференции «LondonJS», и вдохновленном предшествующей ему работой<a l:href=\"#l1\" type=\"note\"><sup>[1]</sup></a> Николаса Закаса.</p></section><section><title><p>Кто я и почему я решил об этом написать?</p></title><p>Меня зовут Эдди Османи. Сейчас я работаю JavaScript- и UI-разработчиком в AOL. Я занимаюсь планированием и написанием фронтенд-архитектуры для следующего поколения наших пользовательских приложений. Эти приложения весьма сложны. Они нуждаются в архитектуре, позволяющей, с одной стороны легко их масштабировать, а с другой достаточно легко использовать повторно их модули. Также я занимаюсь разработкой шаблонов, которые можно применять в разработке приложений подобного масштаба настолько качественно, насколько это вообще возможно.</p><p>Кроме того, я рассматриваю себя как евангелиста шаблонов проектирования (хотя есть много экспертов, разбирающихся в этом лучше меня). В прошлом я написал книгу «Essential JavaScript Design Patterns<a l:href=\"#l2\" type=\"note\"><sup>[2]</sup></a>», а сейчас я занимаюсь написанием более подробного продолжения этой книги.</p></section><section><title><p>Могу ли я уместить эту книгу в 140 символов?</p></title><p>Я уместил эту статью в один твит, на случай, если у вас совсем мало времени:</p><p>Меньше связанности: используйте паттерны «модуль», «фасад» и «медиатор». Модули общаются через медиатор, а фасад обеспечивает безопасность.</p></section></section><section><title><p>Что из себя представляет «большое» JavaScript приложение?</p></title><p>Перед тем как я начну, давайте постараемся определить, что именно мы имеем в виду, когда говорим о больших JavaScript-приложениях. Этот вопрос я считаю своего рода вызовом опытным разработчикам, и ответы на него, соответственно, получаются очень субъективными.</p><p>Ради эксперимента я предложил нескольким среднестатистическим разработчикам дать собственное определение этому термину. Один из разработчиков сказал, что речь идет о «JavaScript-приложениях, состоящих из более чем 100 000 строк кода», когда другой определил что большое приложение «содержит больше чем 1 МБ JavaScript». Я расстроил храбрецов — оба этих варианта далеки от истины. Количество кода не всегда коррелирует со сложностью приложения. 100 000 строк легко могут оказаться самым ничем не примечательным простым кодом.</p><p>Я не знаю, подходит ли мое собственное определение к любому случаю, но я верю, что оно находится ближе всего к тому, что действительно представляет из себя большое JavaScript-приложение.</p><p>Я думаю, что большие JavaScript-приложения решают нетривиальные задачи, а поддержка таких приложений требует от разработчика серьезных усилий. При этом, большая часть работы по манипуляции данными и их отображению ложится на браузер.</p><p>Я думаю, что последняя часть определения — самая важная.</p></section><section><title><p>Давайте обсудим вашу существующую архитектуру</p></title><section><p>Работая над большим JavaScript-приложением, не забывайте уделять <strong>достаточное количество времени</strong> на планирование изначальной архитектуры, к которой такие приложения очень чувствительны. Большие приложения обычно представляют из себя очень сложные системы, гораздо более сложные, чем вы представляете себе изначально.</p><p>Я должен подчеркнуть значение этой разницы — я видел разработчиков, которые, сталкиваясь с большими приложениями, делали шаг назад и говорили: «Хорошо, у меня есть несколько идей, которые хорошо показали себя в моем предыдущем проекте среднего масштаба. Думаю, они точно сработают и для чего-то большего, не так ли?». Конечно, до какого-то момента это может быть так, но, пожалуйста, не принимайте это как должное — по большей части большие приложения имеют ряд достаточно серьезных проблем, с которыми нужно считаться. Ниже я приведу несколько доводов в пользу того, почему вам стоит уделить немного больше времени планированию архитектуры своего приложения, и чем вам это будет полезно в долгосрочной перспективе.</p><p>Большинство JavaScript-разработчиков в архитектуре своих приложений обычно использует различные комбинации следующих компонентов:</p><p>• виджеты</p><p>• модели</p><p>• представления</p><p>• контроллеры</p><p>• шаблоны</p><p>• библиотеки</p><p>• ядро приложения.</p><p><strong>Ссылки по теме:</strong><empty-line />Ребекка Мёрфи — Создание архитектуры JavaScript-приложений<a l:href=\"#l3\" type=\"note\"><sup>[3]</sup></a><empty-line />Питер Мишо — MVC архитектура для JavaScript-приложений<a l:href=\"#l4\" type=\"note\"><sup>[4]</sup></a><empty-line />StackOverflow — Дискуссия о современных MVC-фреймворках<a l:href=\"#l5\" type=\"note\"><sup>[5]</sup></a><empty-line />Дуг Найнер — Поддерживаемые плагины и фабрика виджетов<a l:href=\"#l6\" type=\"note\"><sup>[6]</sup></a></p><p>Вероятно, вы выносите различные функции ваших приложений в отдельные модули, либо используете какие-нибудь другие шаблоны проектирования для подобного разделения. Это очень хорошо, но здесь есть ряд потенциальных проблем, с которыми вы можете столкнуться при таком подходе.</p></section><section><title><p>1. Готова ли ваша архитектура к повторному использованию кода уже сейчас?</p></title><p>Могут ли отдельные модули использоваться самостоятельно? Достаточно ли они автономны для этого? Мог бы я прямо сейчас взять один из модулей вашего большого приложения, просто поместить его на новую веб-страницу, а затем, тут же, начать его использовать? У вас может возникнуть вопрос: «Действительно ли это так необходимо?», но, как бы то ни было, я надеюсь, что вы думаете о будущем. Что, если ваша компания начнет создавать все больше и больше нетривиальных приложений, которые будут иметь некоторую общую функциональность? Если кто-то скажет: «Нашим пользователям очень нравится использовать модуль чата в нашем email-клиенте, почему бы нам не добавить этот модуль к нашему новому приложению для совместной работы с документами?», будет ли это возможно, если мы не уделим должного внимания контролю кода?</p></section><section><title><p>2. Сколько модулей в вашей системе зависит от других модулей?</p></title><p>Насколько сильно связаны ваши модули? Перед тем, как я погружусь в объяснения о том, как важна слабая связанность модулей, я должен отметить, что не всегда есть возможность создавать модули, не имеющие абсолютно никаких зависимостей в системе. К примеру, одни модули могут расширять функции других, уже существующих. Эта тема, скорее всего, относится к группировке модулей на основе некоторой функциональности. Отдельные наборы модулей должны работать в вашем приложении без большого количества зависимостей, чтобы наличие или загрузка других модулей не влияла на их работоспособность.</p></section><section><title><p>3. Сможет ли ваше приложение работать дальше, если его отдельная часть сломается?</p></title><p>Если вы разрабатываете приложения, подобные Gmail, и ваш webmail-модуль (или группа модулей) перестанет работать из-за ошибки, то это не должно заблокировать пользовательский интерфейс или помешать пользователям использовать другие части вашего приложения, к примеру, такие как чат. В то же время, как было сказано раньше, было бы идеально, если бы модули могли работать и за пределами вашей архитектуры. В моей лекции я упоминал динамические зависимости — возможность загружать модули, исходя из определенных действий пользователя. К примеру, ребята из Gmail могли бы изначально держать чат закрытым, не загружая его код при открытии страницы. А в тот момент, когда пользователь решит воспользоваться им — соответствующий модуль будет динамически загружен и выполнен. В идеальном случае хотелось бы выполнить это без каких-то негативных эффектов в вашем приложении.</p></section><section><title><p>4. Насколько легко вы сможете тестировать отдельные модули?</p></title><p>Когда вы работаете над масштабными системами, есть вероятность, что различные части этой системы будут использовать миллионы пользователей. Вполне вероятно, что эти части будут использоваться не только в предусмотренных вами ситуациях. В конечном счете, код может использоваться повторно в огромном количестве различных окружений, и важно, чтобы модули были достаточно протестированы. Тестировать модули необходимо и внутри архитектуры, для которой он был изначально разработан, и снаружи. По моему мнению, это дает наибольшую гарантию того, что модуль не сломается при попадании в другую систему.</p></section></section><section><title><p>Думай о будущем</p></title><p>В процессе создания архитектуры большого приложения, очень важно думать о будущем. Не только о том, что будет через месяц или через год, но и о том, что будет после этого. Что может измениться? Конечно, невозможно достаточно точно предсказать как ваше приложение будет развиваться, но, вне всякого сомнения, имеет смысл подумать об этом. Думаю, что найдется, хотя бы один специфичный аспект вашего приложения, о котором стоит поразмыслить.</p><p>Разработчики зачастую слишком сильно связывают манипуляцию с DOM-элементами и остальные части приложения, даже если до этого они не поленились разделить бизнес-логику на модули. Подумайте, почему в долгосрочной перспективе это может быть плохой идеей?</p><p>Один из слушателей моей лекции предположил, что такая архитектура негибка, и может не работать в будущем. Это действительно так, но есть другая проблема, игнорирование которой окажет еще более негативный эффект.</p><p>В будущем, вы можете принять решение о <strong>замене</strong> Dojo, jQuery, Zepto или YUI на что-нибудь совершенно иное. Причиной такого перехода может быть производительность, безопасность или дизайн. Это может стать серьезной проблемой, потому как библиотеки не предусматривают простой замены. Цена замены библиотеки будет высокой, если ваше приложение тесно с ней связано.</p><p>Если вы используете Dojo (как многие слушатели на моей лекции), вы можете быть уверены, что нет ничего лучше, на что имело бы смысл сейчас перейти. Но можете ли вы быть уверены, что в течении двух-трех лет не появится что-нибудь, что вызовет у вас интерес? Что-нибудь, на что вы можете решить перейти.</p><p>Такое решение может быть достаточно простым для небольших проектов, но <strong>не для больших приложений</strong>, архитектура которых, в целом, достаточна их поддержки.</p><p>Такое решение может быть достаточно простым для небольших проектов, но на <strong>больших приложениях</strong> с непродуманной архитектурой всю тяжесть смены библиотеки вы ощутите сразу.</p><p>Подводя итог, взгляните на вашу архитектуру сейчас. Сможете ли вы сегодня сменить вашу библиотеку на любую другую, не переписывая при этом ваше приложение полностью? Если это не так, то вам стоит продолжить чтение. Я думаю, что в архитектуре, которую мы обсуждаем, вы найдёте кое-что интересное.</p><p>Некоторые из известных JavaScript-разработчиков раньше уже излагали проблемы, о которых я написал выше. Вот три ключевых цитаты, которыми я бы хотел поделиться с вами.</p><p>«Секрет создания больших приложений в том, чтобы никогда не создавать больших приложений. Разбейте ваши приложения на маленькие части, а затем собирайте из этих маленьких тестируемых фрагментов ваше большое приложение» <strong>Джастин Майер, автор «JavaScriptMVC»</strong></p><p>«Секрет в том, чтобы признаться самому себе с самого начала, что вы понятия не имеете о том, как ваше приложение будет развиваться. Когда вы согласитесь с этим, вы начнете проектировать систему основываясь на защите. Вы определите ключевые области, в которых, вероятнее всего будут происходить изменения. Очень часто это не составляет труда, если потратить на это немного времени. К примеру, вы ожидаете, что любая часть приложения, которая взаимодействует с другой системой — это потенциальная мишень для изменений. И вы понимаете, что здесь вам понадобится абстракция».<empty-line /><strong>Николас Закас, автор книги «Высокопроизводительный JavaScript</strong></p><p>И последняя, но тоже очень важная цитата:</p><p>«Чем сильнее компоненты связаны между собой, тем меньше возможностей для их повторного использования, тем сложнее вносить изменения, не получая при этом различных побочных эффектов в самых неожиданных местах» <strong>Ребекка Мёрфи, автор книги «Фундаментальные основы jQuery»</strong></p><p>Эти принципы необходимы для создания архитектуры, способной выдержать испытание временем. Важно всегда помнить о них.</p></section><section><title><p>Мозговой штурм</p></title><section><p>Давайте немного подумаем, что мы хотим получить.</p><p>Мы хотим получить слабосвязанную архитектуру с функциональностью, разделенную на <strong>независимые модули</strong>, которые, в идеале, не должны иметь зависимостей друг от друга. Когда случается что-то интересное, модули <strong>сообщают</strong> об этом другим частям приложения, а промежуточный слой интерпретирует их сообщения и необходимым образом реагирует на них.</p><p>Для примера, у нас есть JavaScript-приложение, отвечающее за онлайн-пекарню. Одно из интересных нам сообщений может быть таким: «Партия из 42 батонов готова к доставке».</p><p>Мы используем отдельный слой для обработки сообщений модулей, чтобы а) модули не взаимодействовали напрямую с ядром, б) модули не взаимодействовали напрямую друг с другом. Это помогает не допустить падения приложения из-за различных ошибок внутри одного из модулей. Также это позволяет нам перезапускать модули если они вдруг перестали работать из-за какой-нибудь ошибки.</p><p>Еще один момент — безопасность. На самом деле, немногие из нас заботятся о внутренней безопасности своих приложений в должной мере. Когда мы определяем структуру приложения, мы говорим себе, что мы достаточно умны для того, чтобы понимать что в нашем коде должно быть публичным, а что приватным.</p><p>Хорошо, но поможет ли это если вы решите определить что именно разрешено модулю выполнять в системе? К примеру, в моем приложении, ограничив доступ из модуля веб-чата к интерфейсу модуля администрирования, я смогу уменьшить шансы на успешное использование XSS уязвимостей, которые я не смог найти в виджете. Модули не должны иметь доступ ко всему. Вероятно, в вашей существующей архитектуре они могут использовать любые части системы, но уверены ли вы, что это действительно необходимо?</p><p>Промежуточный слой, проверяющий имеет ли модуль доступ к определенной части вашего фреймворка, обеспечивает большую безопасность вашей системы. Фактически, это значит что модули могут взаимодействовать только с теми компонентами системы, с которыми мы разрешим им взаимодействовать.</p></section><section><title><p>Архитектура, которую я предлагаю вам</p></title><p>Архитектура, о которой мы говорим, представляет из себя комбинацию трех известных шаблонов проектирования: модуль, фасад и медиатор.</p><p>В отличии от традиционной модели, в которой модули напрямую взаимодействуют друг с другом, в этой слабосвязанной архитектуре модули всего лишь публикуют события (в идеале, не зная о других модулях в системе). Медиатор используется для подписки на сообщения от модулей и для решения, каким должен быть ответ на уведомление. Паттерн фасад используется для ограничения действий разрешенных модулям.</p><p>В следующих главах я более детально расскажу о каждом из этих шаблонов проектирования.</p></section></section><section><title><p>Теория модулей</p></title><p>Вероятно, в каком-то виде вы уже используете модули в своей существующей архитектуре. Если это не так, то в этой главе я покажу вам, как они устроены.</p><p>Модули — это <strong>целая</strong> часть любой хорошей архитектуры приложения. Обычно модули выполняют одну определенную задачу в более крупных системах и могут быть взаимозаменяемы.</p><p>В некоторых реализациях модули могут иметь свои собственные зависимости, которые будут загружены автоматически, собирая вместе таким образом все компоненты системы. Такой подход считается более масштабируемым, в отличие от ручной загрузки модулей или подстановки тега <code>script</code>.</p><p>Каждое нетривиальное приложение должно создаваться из модульных компонентов. Рассмотрим GMail: вы можете рассматривать модули, как независимые единицы функциональности, которые могут и должны существовать сами по себе; возьмём к примеру чат. Скорее всего он основан на своём отдельном модуле чата, но так как этот модуль скорее всего очень сложный, то он вероятно состоит из более мелких вспомогательных модулей. Например, один из таких модулей мог бы отвечать за использование смайликов и он же мог бы использоваться не только в чате, но также и в почте.</p><p>В рассматриваемой архитектуре модули имеют <strong>очень ограниченные знания</strong> о том, что происходит в других частях системы. Вместо этого мы делегируем ответственность медиатору и фасаду.</p><p>В этом и заключается идея нашей архитектуры — если модуль заботится исключительно о том, чтобы уведомить систему об интересующих ее происшествиях, и не волнуется запущены ли другие модули, то система может добавлять, удалять или заменять одни модули, не ломая при этом другие, что было бы невозможно при сильной связанности.</p><p>Слабая связанность — необходимое условие для того, чтобы такая идея была возможна. Она делает поддержку модулей проще, удаляя зависимости в коде там, где это возможно. В вашем случае, одни модули должны работать корректно в не зависимости от того в каком порядке загрузились другие модули. Когда слабая связанность реализована эффективно, становится очевидно, как изменения в одной части системы влияют на другие ее части.</p><p>В JavaScript есть несколько мнений о том, как могут быть реализованы модули, включая шаблон «Модуль» и Object Literal (литеральная запись объекта <code>var obj = {};</code>). Опытные разработчики должно быть уже знакомы с ними. Если это так, то вы можете пропустите следующую главу и перейти сразу к главе «CommonJS Modules».</p></section><section><title><p>Паттерн «Модуль»</p></title><p>«Модуль» — это популярная реализация паттерна, инкапсулирующего приватную информацию, состояние и структуру, используя замыкания. Это позволяет оборачивать публичные и приватные методы и переменные в модули, и предотвращать их попадание в глобальный контекст, где они могут конфликтовать с интерфейсами других разработчиков. Паттерн «модуль» возвращает только публичную часть API, оставляя всё остальное доступным только внутри замыканий.</p><p>Это хорошее решение для того, чтобы скрыть внутреннюю логику от посторонних глаз и производить всю тяжелую работу исключительно через интерфейс, который вы определите для использования в других частях вашего приложения. Этот паттерн очень похож на немедленно-вызываемые функции (IIFE<a l:href=\"#l7\" type=\"note\"><sup>[7]</sup></a>), за тем исключением, что модуль вместо функции, возвращает объект.</p><p>Важно заметить, что в JavaScript нет настоящей приватности. В отличии от некоторых традиционных языков, он не имеет модификаторов доступа. Переменные технически не могут быть объявлены как публичные или приватные, и нам приходится использовать область видимости для того, чтобы эмулировать эту концепцию. Благодаря замыканию, объявленные внутри модуля переменные и методы доступны только изнутри этого модуля. Переменные и методы, объявленные внутри объекта, возвращаемого модулем, будут доступны всем.</p><p>Ниже вы можете увидеть корзину покупок, реализованную с помощью паттерна «модуль». Получившийся компонент находится в глобальном объекте <code>basketModule</code>, и содержит всё, что ему необходимо. Находящийся внутри него, массив <code>basket</code> приватный, и другие части вашего приложения не могут напрямую взаимодействовать с ним. Массив <code>basket</code> существует внутри замыкания, созданного модулем, и взаимодействовать с ним могут только методы, находящиеся в том же контексте (например, <code>addItem()</code>, <code>getItem()</code>).</p><empty-line /><p><code>var basketModule = (function() {</code></p><p><code>  var basket = []; // приватная переменная</code></p><p><code>    return { // методы доступные извне</code></p><p><code>        addItem: function(values) {</code></p><p><code>            basket.push(values);</code></p><p><code>        },</code></p><p><code>        getItemCount: function() {</code></p><p><code>            return basket.length;</code></p><p><code>        },</code></p><p><code>        getTotal: function() {</code></p><p><code>           var q = this.getItemCount(),p=0;</code></p><p><code>            while(q--){</code></p><p><code>                p+= basket[q].price; </code></p><p><code>            }</code></p><p><code>            return p;</code></p><p><code>        }</code></p><p><code>    }</code></p><p><code>}());</code></p><empty-line /><p>Внутри модуля, как вы заметили, мы возвращаем объект. Этот объект автоматически присваивается переменной <code>basketModule</code>, так что с ним можно взаимодействовать следующим образом:</p><empty-line /><p><code>// basketModule - это объект со свойствами, которые могут также быть и методами:</code></p><p><code>basketModule.addItem({item:&#39;bread&#39;, price:0.5});</code></p><p><code>basketModule.addItem({item:&#39;butter&#39;, price:0.3});</code></p><p><code></code></p><p><code>console.log(basketModule.getItemCount());</code></p><p><code>console.log(basketModule.getTotal());</code></p><p><code></code></p><p><code>// А следующий ниже код работать не будет:</code></p><p><code>console.log(basketModule.basket); // undefined потому что не входит в возвращаемый объект</code></p><p><code>console.log(basket); // массив доступен только из замыкания</code></p><empty-line /><p>Методы выше, фактически, помещены в неймспейс <code>basketModule</code>.</p><p>Исторически, паттерн «модуль» был разработан в 2003 году группой людей, в число которых входил Ричард Корнфорд<a l:href=\"#l8\" type=\"note\"><sup>[8]</sup></a>. Позднее, этот паттерн был популяризован Дугласом Крокфордом в его лекциях, и открыт заново в блоге YUI благодаря Эрику Мирагилиа.</p><p>Давайте посмотрим на реализацию «модуля» в различных библиотеках и фреймворках.</p><p><strong>Dojo</strong></p><p>Dojo старается обеспечивать поведение похожее на классы с помощью <code>dojo.declare</code>, который, кроме создания «модулей», также используется и для других вещей. Давайте попробуем, для примера, определить <code>basket</code> как модуль внутри неймспейса <code>store</code>:</p><empty-line /><p><code>// традиционный способ</code></p><p><code>var store = window.store || {};</code></p><p><code>store.basket = store.basket || {};</code></p><p><code></code></p><p><code>// с помощью dojo.setObject</code></p><p><code>dojo.setObject(&quot;store.basket.object&quot;, (function() {</code></p><p><code>    var basket = [];</code></p><p><code>    function privateMethod() {</code></p><p><code>        console.log(basket);</code></p><p><code>    }</code></p><p><code>    return {</code></p><p><code>        publicMethod: function() {</code></p><p><code>            privateMethod();</code></p><p><code>        }</code></p><p><code>    };</code></p><p><code>}()));</code></p><empty-line /><p>Лучшего результата можно добиться, используя <code>dojo.provide</code> и миксины.</p><p><strong>YUI</strong></p><p>Следующий код, по большей части, основан на примере реализации паттерна «модуль» в фреймворке YUI, разработанным Эриком Миргалиа, но более самодокументирован.</p><empty-line /><p><code>YAHOO.store.basket = function () {</code></p><p><code></code></p><p><code>    // приватная переменная:</code></p><p><code>    var myPrivateVar = &quot;Ко мне можно получить доступ только из YAHOO.store.basket.&quot;;</code></p><p><code>    </code></p><p><code>    // приватный метод:</code></p><p><code>    var myPrivateMethod = function() {</code></p><p><code>        YAHOO.log(&quot;Я доступен только при вызове из YAHOO.store.basket&quot;);</code></p><p><code>    }</code></p><p><code>    </code></p><p><code>    return {</code></p><p><code>        myPublicProperty: &quot;Я - публичное свойство&quot;,</code></p><p><code>        myPublicMethod: function() {</code></p><p><code>            YAHOO.log(&quot;Я - публичный метод&quot;);</code></p><p><code>    </code></p><p><code>            // Будучи внутри корзины я могу получить доступ к приватным переменный и методам:</code></p><p><code>            YAHOO.log(myPrivateVar);</code></p><p><code>            YAHOO.log(myPrivateMethod());</code></p><p><code>    </code></p><p><code>            // Родной контекст метода myPublicMethod сохранён</code></p><p><code>            // поэтому мы имеет доступ к this</code></p><p><code>            YAHOO.log(this.myPublicProperty);</code></p><p><code>        }</code></p><p><code>    };</code></p><p><code>    </code></p><p><code>}();</code></p><empty-line /><p><strong>jQuery</strong></p><p>Существует множество способов, чтобы представить jQuery-код в виде паттерна «модуль», даже если этот код не напоминает привычные jQuery-плагины. Бен Черри ранее предлагал способ, при котором, если у модулей есть общие черты, то они объявляются через функцию-обертку.</p><p>В следующем примере функция <code>library</code> используется для объявления новой библиотеки и, автоматически, при создании библиотеки (т.е. модуля), связывает вызов метода <code>init</code> с <code>document.ready</code>.</p><empty-line /><p><code>function library(module) {</code></p><p><code>  $(function() {</code></p><p><code>    if (module.init) {</code></p><p><code>      module.init();</code></p><p><code>    }</code></p><p><code>  });</code></p><p><code>  return module;</code></p><p><code>}</code></p><p><code></code></p><p><code>var myLibrary = library(function() {</code></p><p><code>   return {</code></p><p><code>     init: function() {</code></p><p><code>       /* код модуля */</code></p><p><code>     }</code></p><p><code>   };</code></p><p><code>}());</code></p><empty-line /><p><strong>Ссылки по теме:</strong><empty-line />Бен Черри — Погружение в паттерн «Модуль»<a l:href=\"#l9\" type=\"note\"><sup>[9]</sup></a><empty-line />Джон Ханн — Будущее — это модули, а не фреймворки<a l:href=\"#l10\" type=\"note\"><sup>[10]</sup></a><empty-line />Натан Смит — Ссылки на window и document в модулях (gist)<a l:href=\"#l11\" type=\"note\"><sup>[11]</sup></a></p></section><section><title><p>Литеральная нотация объекта</p></title><p>В литеральной нотации объект описывается внутри блока фигурных скобок (<code>{}</code>), как набор разделенных запятой пар ключ/значение. Ключи объекта могут быть как строками, так и идентификаторами. После имени ставится двоеточие. В объекте не должно стоять запятой после последней пары ключ/значение, так как это может привести к ошибкам.</p><p>Литерал объекта не требует использования оператора <code>new</code> для создания экземпляра, но он не должен стоять в начале выражения, так как открытая <code>{</code> может быть воспринята как начало блока. Ниже вы можете увидеть пример модуля, определенного с помощью литеральной нотации объекта. Новые члены объекта могут быть добавлены с помощью конструкции <code>myModule.property = &#39;someValue&#39;;</code></p><p>Паттерн «модуль» может быть полезен для многих вещей. Но если вы считаете, что вам не нужно делать приватными некоторые методы или свойства, то литерал объекта — более чем подходящий выбор.</p><empty-line /><p><code>var myModule = {</code></p><p><code>    myProperty: &#39;someValue&#39;,</code></p><p><code>    // Литералы объектов могут содержать свойства и методы.</code></p><p><code>    // ниже в свойстве определен другой объект,</code></p><p><code>    // для описания конфигурации:</code></p><p><code>    myConfig: {</code></p><p><code>        useCaching: true,</code></p><p><code>        language: &#39;en&#39;</code></p><p><code>    },</code></p><p><code>    // Очень простой метод</code></p><p><code>    myMethod: function() {</code></p><p><code>        console.log(&#39;I can haz functionality?&#39;);</code></p><p><code>    },</code></p><p><code>    // вывод значения заданного в конфигурации</code></p><p><code>    myMethod2: function() {</code></p><p><code>        console.log(&#39;Caching is: &#39; + ((this.myConfig.useCaching) ? &#39;enabled&#39; : &#39;disabled&#39;));</code></p><p><code>    },</code></p><p><code>    // переопределение конфигурации</code></p><p><code>    myMethod3: function(newConfig) {</code></p><p><code>        if (typeof newConfig == &#39;object&#39;) {</code></p><p><code>            this.myConfig = newConfig;</code></p><p><code>            console.log(this.myConfig.language); </code></p><p><code>        }</code></p><p><code>    }</code></p><p><code>};</code></p><p><code></code></p><p><code>myModule.myMethod();  // &#39;I can haz functionality&#39;</code></p><p><code>myModule.myMethod2(); // Вывод &#39;enabled&#39;</code></p><p><code>myModule.myMethod3({language:&#39;fr&#39;,useCaching:false}); // &#39;fr&#39;</code></p><empty-line /><p><strong>Ссылки по теме:</strong><empty-line />Ребекка Мёрфи — Использование объектов для организации вашего кода<a l:href=\"#l12\" type=\"note\"><sup>[12]</sup></a><empty-line />Стоян Стефанов — 3 способа определения класса в JavaScript<a l:href=\"#l13\" type=\"note\"><sup>[13]</sup></a><empty-line />Бен Алман — Разъяснения по литералам объектов (понятия JSON-объект не существует)<a l:href=\"#l14\" type=\"note\"><sup>[14]</sup></a><empty-line />Джон Резиг - Простое наследование в JavaScript<a l:href=\"#l15\" type=\"note\"><sup>[15]</sup></a></p></section><section><title><p>CommonJS Модули</p></title><p>Возможно, вы что-то слышали о CommonJS<a l:href=\"#l16\" type=\"note\"><sup>[16]</sup></a> за последние пару лет. CommonJS — это добровольная рабочая группа, которая проектирует, прототипирует и стандартизирует различные JavaScript API. На сегодняшний день они ратифицировали стандарты для модулей и пакетов — CommonJS определяют простой API для написания модулей, которые могут быть использованы в браузере с помощью тега <code>&lt;script&gt;</code>, как с синхронной, так и с асинхронной загрузкой. Реализация паттерна «модуль» с помощью CommonJS выглядит очень просто, и я нахожу это уверенным шагом на пути к модульной системе, предложенной в ES Harmony (следующей версии JavaScript).</p><p>В структурном плане, CommonJS-модуль представляет собой готовый к переиспользованию фрагмент JavaScript-кода, который экспортирует специальные объекты, доступные для использования в любом зависимом коде. CommonJS все чаще используется как стандартный формат JavaScript-модулей. Существует большое количество хороших уроков по написанию CommonJS-модулей, но обычно они описывают две главных идеи: объект <code>exports</code>, содержащий то, что модуль хочет сделать доступным для других частей системы, и функцию <code>require</code>, которая используется одними модулями для импорта объекта <code>exports</code> из других.</p><empty-line /><p><code>/*</code></p><p><code>Пример обеспечения совместимости между AMD и обычным CommonJS с помощью</code></p><p><code>создания обертки над последним:</code></p><p><code>*/</code></p><p><code></code></p><p><code>(function(define) {</code></p><p><code>define(function(require,exports) {</code></p><p><code>  // module contents</code></p><p><code>  var dep1 = require(&quot;dep1&quot;);</code></p><p><code>  exports.someExportedFunction = function() {...};</code></p><p><code>  //...</code></p><p><code>});</code></p><p><code>})(typeof define==&quot;function&quot;?define:function(factory){factory(require,exports)});</code></p><empty-line /><p>Есть много хороших JavaScript-библиотек, для загрузки модулей в формате <strong>CommonJS</strong>, но моим личным предпочтением является RequireJS. Полный учебник по RequireJS выходит за рамки этого руководства, но я могу порекомендовать вам почитать пост Джеймса Брука «ScriptJunkie»<a l:href=\"#l17\" type=\"note\"><sup>[17]</sup></a>. Кроме того, я знаю многих людей, которые предпочитают Yabble.</p><p>Из коробки, RequireJS уже содержит методы для простого создания статичных модулей с обертками. Благодаря этим методам становится действительно легко создавать модули с поддержкой асинхронной загрузки. RequireJS может легко загружать модули и их зависимости, выполняя тело модуля, сразу, как только это становится возможным.</p><p>Некоторые разработчики утверждают, что CommonJS-модули не достаточно удобны для применения в браузере, потому как без определенной помощи со стороны сервера, их нельзя загрузить с помощью тега <code>script</code>. Давайте представим, что есть некая библиотека для кодирования изображений в виде ASCII-изображений, которая экспортирует функцию <code>encodeToASCII</code>. Модуль использующий эту библиотеку будет выглядеть примерно так:</p><empty-line /><p><code>var encodeToASCII = require(&quot;encoder&quot;).encodeToASCII;</code></p><p><code>exports.encodeSomeSource = function() {</code></p><p><code>  // Обработка изображения, затем вызов encodeToASCII</code></p><p><code>}</code></p><empty-line /><p>Этот код не будет работать с тегом <code>script</code>. Ему необходим определенный контекст. Я имею в виду наш метод <code>encodeToASCII</code>, который ссылается на несуществующие в контексте <code>window</code> методы <code>require</code> и <code>exports</code>. В такой ситуации нам пришлось бы писать <code>require</code> и <code>exports</code> для каждого отдельного модуля. Эту проблему легко решают клиентские библиотеки, которые загружают скрипты через XHR-запросы, а затем выполняют <code>eval()</code>.</p><p>Попробуем переписать этот модуль, используя RequireJS:</p><empty-line /><p><code>define(function(require, exports, module) {</code></p><p><code>  var encodeToASCII = require(&quot;encoder&quot;).encodeToASCII;</code></p><p><code>  exports.encodeSomeSource = function() {</code></p><p><code>    // Обработка изображения, затем вызов encodeToASCII</code></p><p><code>  }</code></p><p><code>});</code></p><empty-line /><p>Для разработчиков, которые хотят пойти дальше простого использования JavaScript в своих проектах, CommonJS модули — прекрасная возможность начать движение в эту сторону, но придется потратить немного времени и познакомиться поближе с этим форматом. Все, что я рассказал — это только верхушка айсберга. К счастью, CommonJS wiki и SitePen содержат много материалов, которые помогут вам глубже разобраться в устройстве CommonJS-модулей.</p><p><strong>Ссылки по теме:</strong><empty-line />Спецификации CommonJS-модулей<a l:href=\"#l18\" type=\"note\"><sup>[18]</sup></a><empty-line />Алекс Янг - Прояснение CommonJS-модулей<a l:href=\"#l19\" type=\"note\"><sup>[19]</sup></a><empty-line />Заметки о CommonJS- и RequireJS-модулях<a l:href=\"#l20\" type=\"note\"><sup>[20]</sup></a></p></section><section><title><p>Паттерн «Фасад»</p></title><p>Ключевую роль в архитектуре, которую мы обсуждаем в этой книге, играет шаблон проектирования под названием «фасад».</p><p>Как правило, фасад используется для создания некоторой абстракции, скрывающей за собой совершенно иную реальность. Паттерн «фасад» обеспечивает удобный <strong>высокоуровневый интерфейс</strong> для больших блоков кода, скрывая за собой их истинную сложность. Относитесь к фасаду, как к упрощенному API, который вы отдаете в пользование другим разработчикам.</p><p>Фасад — <strong>структурный паттерн</strong>. Часто его можно обнаружить в JavaScript-библиотеках и фреймворках, где пользователям доступнен только фасад — ограниченная абстракция широкого диапазона поведений реализованных внутри.</p><p>Благодаря такому подходу, пользователь взаимодействует только с интерфейсом, не имея никакого представления о подсистемах, которые скрываются за ним.</p><p>Причина, по которой нам интересен фасад — возможность скрыть детали реализации конкретной функциональности, хранящиеся в модулях. Это позволит нам вносить изменения в реализацию, не сообщая об этом пользователям.</p><p>Надежный фасад — наш упрощенный интерфейс — позволит нам не беспокоиться о тесных связях некоторых модулей нашей системы с dojo, jQuery, YUI, zepto или какой-либо другой библиотекой. Это становится не так важно. Вы можете переходить с одной библиотеки на другую не меняя слой взаимодействия. К примеру, с jQuery на dojo. Более того, у вас появляется возможность совершить такой переход на более поздних этапах, без изменений в остальных частях системы.</p><p>Ниже я написал достаточно простой пример использования фасада. Как вы видите, у нашего модуля есть несколько приватных методов. Чтобы создать более простой интерфейс для доступа к этим методам мы используем фасад.</p><empty-line /><p><code>var module = (function() {</code></p><p><code>  var _private = {</code></p><p><code>    i: 5,</code></p><p><code>    get: function() {</code></p><p><code>      console.log(&#39;Текущее значение:&#39; + this.i);</code></p><p><code>    },</code></p><p><code>    set: function(val) {</code></p><p><code>      this.i = val;</code></p><p><code>    },</code></p><p><code>    run: function() {</code></p><p><code>      console.log(&#39;процесс запущен&#39;);</code></p><p><code>    },</code></p><p><code>    jump: function() {</code></p><p><code>      console.log(&#39;резкое изменение&#39;);</code></p><p><code>    }</code></p><p><code>  };</code></p><p><code>  return {</code></p><p><code>    facade: function(args) {</code></p><p><code>      _private.set(args.val);</code></p><p><code>      _private.get();</code></p><p><code>      if (args.run) {</code></p><p><code>        _private.run();</code></p><p><code>      }</code></p><p><code>    }</code></p><p><code>  }</code></p><p><code>}());</code></p><p><code></code></p><p><code>module.facade({run:true, val:10}); // Текущее значение: 10, процесс запущен</code></p><empty-line /><p>Это и есть та причина, по которой мы добавили фасад к нашей архитектуре. В следующей главе мы обсудим медиатор. Принципиальное различие между этими двумя паттернами заключается в том, что фасад, как структурный паттерн, всего лишь передает существующую функциональность в медиатор, в то время как медиатор, как поведенческий паттерн, может эту функциональность расширять.</p><p><strong>Ссылки по теме:</strong><empty-line />Дастин Диас, Росс Хармс — «Профессиональные шаблоны проектирования JavaScript» (Глава 10, доступно для чтения в Google Books)<a l:href=\"#l21\" type=\"note\"><sup>[21]</sup></a></p></section><section><title><p>Паттерн «Медиатор»</p></title><p>Объяснить, что представляет собой паттерн «медиатор» достаточно просто на примере следующей аналогии — представьте себе контроль траффика в аэропорте: все решения о том, какие самолеты могут взлетать или садиться, принимает диспетчер. Для этого, все сообщения, исходящие от самолетов, поступают в башню управления, вместо того, чтобы пересылаться между самолетами напрямую. Такой централизованный контроллер — это и есть ключ к успеху нашей системы. Это и есть «медиатор».</p><p>Медиатор применяется в системах, где взаимодействие между модулями может быть весьма сложными, но, в то же время, <strong>хорошо определенными</strong>. Если вы полагаете, что связи между модулями вашей системы будут постоянно расти и усложняться, то, возможно, вам стоит добавить центральный элемент управления. Паттерн «медиатор» отлично подходит для этой роли.</p><p>Медиатор выступает в качестве посредника в общении между различными модулями, <strong>инкапсулируя их взаимодействие</strong>. Кроме того, этот шаблон проектирования, предотвращая прямое взаимодействие различных компонентов системы, способствует ослаблению связей в коде. В нашей системе он так же помогает в решении проблем, связанных с зависимостями модулей.</p><p>Какие еще преимущества существуют у «медиатора»? К примеру, медиатор позволяет каждому модулю функционировать абсолютно независимо от других компонентов системы, что приводит к большей гибкости. Если вам ранее уже приходилось использовать паттерн «наблюдатель» в роли системы доставки событий между различными частями в вашей системе, то вам не составит труда разобраться с медиатором.</p><p>Давайте посмотрим на модель взаимодействия модулей и медиатора:</p><image l:href=\"#image1\" l:type=\"imageType\" alt=\"\" /><p>Мы можем рассматривать модули, как «издателей», публикующих события. Медиатор же является и «издателем» и «подписчиком» одновременно. В примере, <code>Module 1</code> посылает сообщение, предполагающее некоторую реакцию, медиатору. Затем, медиатор, получив сообщение, уведомляет другие модули об определенных действиях, которые необходимо выполнить для завершения задачи. <code>Module 2</code> выполняет необходимые <code>Module 1</code> действия, и сообщает о результате обратно, в медиатор. В это же время, медиатор запускает <code>Module 3</code> для логгирования поступающих сообщений.</p><p>Обратите внимание: здесь нет прямого взаимодействия между модулями. Если в <code>Module 3</code> произойдет ошибка или, к примеру, он просто перестанет работать, то медиатор, теоретически, может приостановить выполнение задач в других модулях, затем перезапустить <code>Module 3</code> и продолжить работу, практически не влияя на работу всей системы. Такая слабая связанность модулей является одним из самых сильных преимуществ паттерна «медиатор», который я вам предлагаю использовать.</p><p>Посмотрим на его преимущества:</p><p>Уменьшает связывание модулей, добавляя посредника — центральный элемент управления. Это позволяет модулям отправлять и слушать сообщения, не затрагивая остальной части системы. Сообщения могут быть обработаны любым количеством модулей сразу.</p><p>Благодаря слабой связанности кода, внедрение новой функциональности происходит существенно легче.</p><p>И недостатки:</p><p>Модули больше не могут взаимодействовать напрямую. Использование медиатора приводит к небольшому падению производительности — такова природа слабой связанности — становится достаточно трудно определить реакцию системы, отталкиваясь только от событий, происходящих в ней.</p><p>Наконец, системы с высокой связанностью кода являются обычно источником всевозможных проблем, решением которых может стать уменьшение связанности.</p><p><strong>Пример:</strong> одна из возможных реализаций паттерна «медиатор», основанная на работе [@rpflorence]10-8<a l:href=\"#l22\" type=\"note\"><sup>[22]</sup></a></p><empty-line /><p><code>var mediator = (function() {</code></p><p><code>    var subscribe = function(channel, fn) {</code></p><p><code>        if (!mediator.channels[channel]) mediator.channels[channel] = [];</code></p><p><code>        mediator.channels[channel].push({ context: this, callback: fn });</code></p><p><code>        return this;</code></p><p><code>    },</code></p><p><code> </code></p><p><code>    publish = function(channel) {</code></p><p><code>        if (!mediator.channels[channel]) return false;</code></p><p><code>        var args = Array.prototype.slice.call(arguments, 1);</code></p><p><code>        for (var i = 0, l = mediator.channels[channel].length; i &lt; l; i++) {</code></p><p><code>            var subscription = mediator.channels[channel][i];</code></p><p><code>            subscription.callback.apply(subscription.context, args);</code></p><p><code>        }</code></p><p><code>        return this;</code></p><p><code>    };</code></p><p><code> </code></p><p><code>    return {</code></p><p><code>        channels: {},</code></p><p><code>        publish: publish,</code></p><p><code>        subscribe: subscribe,</code></p><p><code>        installTo: function(obj) {</code></p><p><code>            obj.subscribe = subscribe;</code></p><p><code>            obj.publish = publish;</code></p><p><code>        }</code></p><p><code>    };</code></p><p><code></code></p><p><code>}());</code></p><empty-line /><p>И два примера использования реализации, написанной выше:</p><empty-line /><p><code>//Pub/sub on a centralized mediator</code></p><p><code></code></p><p><code>mediator.name = &quot;tim&quot;;</code></p><p><code>mediator.subscribe(&#39;nameChange&#39;, function(arg) {</code></p><p><code>    console.log(this.name);</code></p><p><code>    this.name = arg;</code></p><p><code>    console.log(this.name);</code></p><p><code>});</code></p><p><code></code></p><p><code>mediator.publish(&#39;nameChange&#39;, &#39;david&#39;); //tim, david</code></p><p><code></code></p><p><code></code></p><p><code>//Pub/sub via third party mediator</code></p><p><code></code></p><p><code>var obj = {name: &#39;sam&#39;};</code></p><p><code>mediator.installTo(obj);</code></p><p><code>obj.subscribe(&#39;nameChange&#39;, function(arg) {</code></p><p><code>    console.log(this.name);</code></p><p><code>    this.name = arg;</code></p><p><code>    console.log(this.name);</code></p><p><code>});</code></p><p><code></code></p><p><code>obj.publish(&#39;nameChange&#39;, &#39;john&#39;); //sam, john</code></p><empty-line /><p><strong>Ссылки по теме:</strong><empty-line />Stoyan Stefanov — Page 168, JavaScript Patterns<empty-line />HB Stone — Шаблоны проектирования JavaScript: Медиатор<a l:href=\"#l23\" type=\"note\"><sup>[23]</sup></a><empty-line />NVince Huston — Шаблон Медиатора (не относится JavaScript, но кратко)<a l:href=\"#l24\" type=\"note\"><sup>[24]</sup></a></p></section><section><title><p>Использование фасада: абстракция ядра</p></title><p>Фасад, в нашей архитектуре, выполняет роль <strong>абстракции</strong> ядра приложения. Фасад находится между медиатором и модулями. Модули в идеальной ситуации должны взаимодействовать <strong>исключительно</strong> с фасадом и не должны знать абсолютно ничего о других компонентах нашей системы.</p><p>Фасад также обеспечивает <strong>последовательный и доступный в любой момент интерфейс</strong> для модулей. Это похоже на <strong>песочницу</strong> в архитектуре Николаса Закаса.</p><p>Все сообщения от модулей, адресованные медиатору, проходят через фасад, поэтому он должен быть весьма надежен. Его роль в этом взаимодействии — анализ сообщений, исходящих от модулей, и передача этих сообщений в медиатор.</p><p>В дополнение к предоставлению интерфейса, фасад также выступает в роли защиты, определяя с какими частями системы может взаимодейстовать модуль. Модули могут вызывать только <strong>свои собственные</strong> методы. Для доступа к другим компонентам системы модулям необходимо иметь специальное разрешение.</p><p>К примеру, модуль может отправить сообщение <code>dataValidationCompletedWriteToDB</code>. В подобных случаях задача фасада — убедиться, действительно ли этот модуль имеет права на запись в базу данных. Таким образом, мы пытаемся предотвратить проблемы с модулями, которые пытаются делать то, что они не должны.</p><p>Подведем итоги: медиатор представляет собой интерпретацию паттерна «подписчик/издатель», но он получает только те сообщения, которые нас действительно интересуют. За фильтрацию же всех сообщений отвечает фасад.</p></section><section><title><p>Использование медиатора: ядро приложения</p></title><p>В этой главе мы кратко пройдемся по некоторым зонам ответственности медиатора, который играет роль ядра приложения. Но, для начала, давайте разберемся, что он представляет собой в целом.</p><p>Основная задача ядра — управлять <strong>жизненным циклом</strong> модулей. Когда ядро получает <strong>интересное сообщение</strong> от модулей, оно должно определить, как приложение должно на это отреагировать, таким образом ядро определяет момент <strong>запуска</strong> или <strong>остановки</strong> определенного модуля или набора модулей.</p><p>В идеальной ситуации, однажды запущенный модуль, должен функционировать самостоятельно. В задачи ядра не входит принятие решений о том, как реагировать, например, на событие <code>DOM ready</code> — в нашей архитектуре у модулей есть достаточно возможностей для того, чтобы принимать такие решения самостоятельно.</p><p>Возможно, у вас вызовет удивление то обстоятельство, что модулям может потребоваться остановка. Такое может произойти случае, если модуль вышел из строя, либо если в работе модуля происходят серьезные ошибки. Решение об остановке модуля может помочь предотвратить некорректную работу его методов. Последующий перезапуск таких модулей должен помочь решить возникшие проблемы. Цель здесь в минимизации негативных последствий для пользователя нашего приложения.</p><p>В дополнение, ядро должно быть в состоянии <strong>добавлять или удалять</strong> модули не ломая ничего. Типичный пример — определенный набор функций может быть недоступен на начальном этапе загрузки страницы, но эти функции могут быть загружены динамически, на основе определенных действий со стороны пользователя. Возвращаясь к нашему примеру с GMail, google может, по умолчанию, держать чат в свернутом состоянии и загружать соответствующий ему модуль динамически, только в том случае, если пользователь проявит интерес к использованию этой части приложения. С точки зрения оптимизации производительности, это должно дать заметный эффект.</p><p>Обслуживание ошибок должно также обрабатываться ядром приложения. В добавок к сообщению об интересных событиях модули также должны сообщать и о любых ошибках которые произошли в их работе. Ядро должно соответствующим образом реагировать на эти ошибки (к примеру, останавливать модули, перезапускать их и тд). Это важно, как часть слабо связанной архитектуры, позволяющей реализовать новый или лучший подход к реализации уведомления пользователя об ошибках без ручного изменения в каждом модуле. Используя механизм для публикации событий и подписки на них в медиаторе мы сможем достичь этого.</p></section><section><title><p>Собираем всех вместе</p></title><p>• <strong>Модули</strong> содержат специфичные части функциональности вашего приложения. Они публикуют уведомления, информирующие приложение о том, что случилось что-то интересное. Это их главная забота. Как я поясню в FAQ, модули могут зависеть от различных вспомогательных методов для работы с DOM, но идеальным бы было отсутствие любых зависимостей от других компонентов системы. Модули не должны иметь отношение к тому:<empty-line /><p>◦ какие объекты или модули подписаны на их сообщения,</p><p>◦ где находятся эти объекты (на клиенте или на сервере),</p><p>◦ какое количество объектов подписано на уведомления.</p></p><p><strong></strong></p><p>• <strong>Фасад</strong> — абстракция ядра защищающая его от прямого контакта с модулями. Он подписывается на интересные сообщения от модулей, и говорит: «Отлично! Что случилось? Расскажи мне больше подробностей!». Так же фасад поддерживает безопасность модулей, проверяя, действительно ли модуль, отправивший сообщение, имеет необходимые права для того, чтобы его сообщение было соответствующим образом обработано ядром.</p><p><strong></strong></p><p>• <strong>Медиатор (ядро приложения)</strong> выступает в роли управляющего публикациями событий и подписками на них. Он отвечает за управление запуском и остановку модулей по необходимости. Здесь используется частичная динамическая загрузка зависимостей, и гарантия того, что упавшие модули могут быть централизованно перезапущены в случае проблем.</p><p><strong></strong></p><p>Итог этой архитектуры в том, что модули, в большинстве случаев, практически не зависят от других компонентов приложения. Они могут быть легко тестируемы и легко поддерживаемы в рамках своего кода. Кроме того, благодаря низкому уровню связанности кода, такие модули можно легко скопировать на новую страницу для использования в другом проекте, не прилагая дополнительных усилий. Так же, эти модули могут быть загружены или удалены динамически в процессе работы приложения.</p></section><section><title><p>Развитие идей медиатора: автоматическая регистрация событий</p></title><p>Как раньше упоминал Михаэль Махемофф, размышляя о больших и масштабируемых JavaScript-приложениях, весьма выгодно использовать в приложении больше динамических свойств языка. Вы можете прочитать об этом больше в его заметках на странице Google+<a l:href=\"#l25\" type=\"note\"><sup>[25]</sup></a>, но я хочу подробнее остановиться на одной особенности — автоматической регистрации событий (AER).</p><p>AER решает проблему связывания подписчиков и издателей путем добавления паттерна, который автоматически вызывает нужные методы на основе соглашения об именовании. Для примера, если модуль публикует сообщение <code>messageUpdate</code>, произойдет автоматический вызов одноименного метода у всех модулей, которые такой имеют.</p><p>Использование этого паттерна подразумевает регистрацию всех компонентов, которые могут подписываться на события, регистрацию всех событий на которые можно подписаться и, наконец, для каждого метода подписки в вашем наборе компонентов должно быть событие. Это выглядит очень интересно по отношению к нашей архитектуре, но так же имеет ряд интересных проблем.</p><p>К примеру, при работе динамически, объекты должны регистрировать себя после создания. Если вас это заинтересовало — посмотрите пост<a l:href=\"#l26\" type=\"note\"><sup>[26]</sup></a> Михаэля об AER, где он более подробно обсуждает как бороться с проблемами этого подхода.</p></section><section><title><p>Frequently Asked Questions</p></title><section><title><p>Возможно ли обойтись без использования фасада (песочницы)?</p></title><p>Хотя архитектура, которую я изложил здесь, использует фасад для обеспечения безопасности, вполне возможно достичь того же с помощью медиатора — сообщения могут обрабатываться непосредственно ядром без использования фасада. Такая упрощенная версия все равно будет обеспечивать необходимо низкий уровень связывания кода, но при выборе этого варианта, нужно понимать, насколько вам будет комфортно работать с модулями, которые взаимодействуют напрямую с ядром.</p></section><section><title><p>В книге говорилось о том, что модули не должны иметь любых зависимостей, касается ли это библиотек (к примеру, jQuery)</p></title><p>Я специально вынес вопрос о зависимостях от других модулей сюда. Когда некоторые разработчики выбирают подобную архитектуру, этот выбор подразумевает что они будут использовать определенные абстракции от DOM-библиотек. К примеру, вы можете использовать вспомогательную утилиту, которая будет возвращать нужные вам DOM-элементы используя jQuery (или dojo). Благодаря этому, модули все еще могут удобно работать с DOM, но уже будут это делать не напрямую, жестко используя конкретную библиотеку. Существует достаточно много способов, как сделать модули независимыми, но стоит понимать, что, в обсуждаемой нами архитектуре, идеальные модули не должны иметь зависимостей.</p><p>Вы заметите, что иногда при таком подходе становится гораздо легче взять законченный модуль из одного проекта и перенести его в другой проект с небольшими дополнительными усилиями. Должен сказать, я полностью согласен с тем, что порой намного лучше, когда модули, вместо определенной части своей функциональности, просто используют другие модули. Как бы то ни было, держите в голове то, что такие модули, в некоторых случаях, могут потребовать гораздо больше усилий для переноса в другой проект.</p></section><section><title><p>Я хочу сегодня же начать использовать эту архитектуру. Есть ли какой-то шаблон от которого я бы мог оттолкнуться?</p></title><p>Когда у меня будет немного свободного времени, я планирую написать для этой книги бесплатный шаблон проекта, но сейчас, наверное, лучший выбор — платное учебное пособие написанное Эндрю Бэджис — «Написание модульного JavaScript»<a l:href=\"#l27\" type=\"note\"><sup>[27]</sup></a> (разоблачу себя: деньги от этой реферальной ссылки, как и любые другие, полученные от этой книги деньги уже инвестируются в обзор будущих материалов перед тем, как я порекомендую их другим). Пособие Эндрю включает в себя скринкаст и примеры кода. Оно охватывает большую часть идей, которые мы обсуждали в книге, но в нем, вместо названия «фасад» используется слово «песочница», как у Николаса Закаса. Так же, здесь есть обсуждение о том, что работа с DOM-библиотеками, в идеале, должна быть реализована посредством абстракции. Я говорил об этом в предыдущем вопросе. Тут Эндрю делает ставку на некоторые интересные шаблоны, обобщающие работу с селекторами DOM, таким образом, в крайнем случае, замена библиотеки может быть выполнена в несколько коротких строк. Я не говорю, что это лучший или самый правильный подход, но я поступаю именно так.</p></section><section><title><p>Могут ли модули взаимодействовать с ядром напрямую, если это необходимо?</p></title><p>Как заметил раньше Николас Закас, технически, нет никаких причин, мешающих модулям напрямую обращаться к ядру. Это скорее относится к «лучшим практикам». Если вы намерены строго следовать этой архитектуре, то вы должны также следовать ее правилам. Либо следовать правилам более простой архитектуры, которая была описана в первом вопросе.</p></section></section><section><title><p>Credits</p></title><p>Спасибо Николасу Закасу за его оригинальную работу в объединении большого количества концепций существующих на сегодняшний день. Спасибо Андрэ Хэнссон за технический обзор книги и за отзывы, которые помогли сделать эту книгу лучше. Спасибо Ребекке Мюрфей, Джастину Майеру, Питеру Мишо, Полу Айришу и Алексу Секстону и всем, чьи материалы относятся к теме обсуждаемой в книге и являлись источником вдохновения как для меня так и для других.</p></section></section></body><body name=\"notes\"><section id=\"l1\"><title><p>1</p></title><p><code>http://yuilibrary.com/theater/nicholas-zakas/zakas-architecture/</code></p></section><section id=\"l2\"><title><p>2</p></title><p><code>http://addyosmani.com/resources/essentialjsdesignpatterns/book/</code></p></section><section id=\"l3\"><title><p>3</p></title><p><code>http://rmurphey.com/blog/2010/08/27/code-org-take-2-structuring-javascript-applications/</code></p></section><section id=\"l4\"><title><p>4</p></title><p><code>http://michaux.ca/articles/mvc-architecture-for-javascript-applications</code></p></section><section id=\"l5\"><title><p>5</p></title><p><code>http://stackoverflow.com/questions/5112899/knockout-js-vs-backbone-js-vs</code></p></section><section id=\"l6\"><title><p>6</p></title><p><code>http://msdn.microsoft.com/en-us/scriptjunkie/ff706600</code></p></section><section id=\"l7\"><title><p>7</p></title><p><code>http://benalman.com/news/2010/11/immediately-invoked-function-expression/</code></p></section><section id=\"l8\"><title><p>8</p></title><p><code>http://groups.google.com/group/comp.lang.javascript/msg/9f58bd11bd67d937</code></p></section><section id=\"l9\"><title><p>9</p></title><p><code>http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth</code></p></section><section id=\"l10\"><title><p>10</p></title><p><code>http://lanyrd.com/2011/jsconf/sfgdk/</code></p></section><section id=\"l11\"><title><p>11</p></title><p><code>https://gist.github.com/274388</code></p></section><section id=\"l12\"><title><p>12</p></title><p><code>http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code</code></p></section><section id=\"l13\"><title><p>13</p></title><p><code>http://www.phpied.com/3-ways-to-define-a-javascript-class/</code></p></section><section id=\"l14\"><title><p>14</p></title><p><code>http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/</code></p></section><section id=\"l15\"><title><p>15</p></title><p><code>http://ejohn.org/blog/simple-javascript-inheritance/</code></p></section><section id=\"l16\"><title><p>16</p></title><p><code>http://commonjs.org</code></p></section><section id=\"l17\"><title><p>17</p></title><p><code>http://msdn.microsoft.com/en-us/scriptjunkie/ff943568</code></p></section><section id=\"l18\"><title><p>18</p></title><p><code>http://wiki.commonjs.org/wiki/Modules</code></p></section><section id=\"l19\"><title><p>19</p></title><p><code>http://dailyjs.com/2010/10/18/modules/</code></p></section><section id=\"l20\"><title><p>20</p></title><p><code>http://requirejs.org/docs/commonjs.html#packages</code></p></section><section id=\"l21\"><title><p>21</p></title><p><code>http://books.google.co.uk/books?id=za3vlnlWxb0C&amp;lpg=PA141&amp;ots=MD5BLTsSzH&amp;dq=javascript%20facade%20pattern&amp;pg=PA141#v=onepage&amp;q=javascript%20facade%20pattern&amp;f=false</code></p></section><section id=\"l22\"><title><p>22</p></title><p><code>https://github.com/rpflorence</code></p></section><section id=\"l23\"><title><p>23</p></title><p><code>http://arguments.callee.info/2009/05/18/javascript-design-patterns--mediator/</code></p></section><section id=\"l24\"><title><p>24</p></title><p><code>http://www.vincehuston.org/dp/mediator.html</code></p></section><section id=\"l25\"><title><p>25</p></title><p><code>https://plus.google.com/106413090159067280619/posts/hDZkVrDXZR6</code></p></section><section id=\"l26\"><title><p>26</p></title><p><code>http://softwareas.com/automagic-event-registration</code></p></section><section id=\"l27\"><title><p>27</p></title><p><code>http://bit.ly/orGVOL</code></p></section></body><binary id=\"image1\" content-type=\"image/jpeg\">R0lGODlh0AIpAcQAANbW1vz8/L+/v/X19YeHh8PDwwICAjIyMqWlpZaWlmZmZvr6+u3t7fLy8s/Pz0RERFZWVrW1tTg4OH19ffj4+NnZ2eTk5K6urtzc3CkpKdPT03Nzc/7+/s3NzTAwMP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4zLWMwMTEgNjYuMTQ1NjYxLCAyMDEyLzAyLzA2LTE0OjU2OjI3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDQTAyMThGQTcyMUQxMUUzQTlDQUU4MTkyRTVBQTQyOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDQTAyMThGOTcyMUQxMUUzQTlDQUU4MTkyRTVBQTQyOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M2IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSI1OEYyODVDNzZDQTlBQkRFODAwREIyREY2MkZEQzJERSIgc3RSZWY6ZG9jdW1lbnRJRD0iNThGMjg1Qzc2Q0E5QUJERTgwMERCMkRGNjJGREMyREUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4B//79/Pv6+fj39vX0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</binary></FictionBook>"
  },
  {
    "path": "humans.txt",
    "content": "# humanstxt.org/\n# The humans responsible & technology colophon\n\n# TEAM\n\n    Антон Шувалов -- Идея, перевод, создание сайта -- @shuvalov_anton\n    Рахим Давлеткалиев -- Вычитывание и редактура -- @freetonik\n    Владимир Старков -- Помощь с джекиллом, вычитывание и редактура -- @matmuchrapna\n\n# TECHNOLOGY COLOPHON\n\n    HTML5, CSS3, reset.css\n    Jekyll, prose.io/, Github pages\n\n    Source: https://github.com/shuvalov-anton/largescaleJS_ru\n"
  },
  {
    "path": "index.md",
    "content": "---\nlayout: page\ntitle: \"Паттерны для масштабируемых JavaScript-приложений\"\nsubtitle: \"<a href='http://addyosmani.com/largescalejavascript/'>Оригинал.</a> Автор: <a href='http://twitter.com/addyosmani'>Эдди Османи</a>. Техническая редактура: <a href='http://twitter.com/peolanha'>Андрэ Хэнсон</a>\"\nindex: true\n---\n\n{% include translation/rus/readme.md %}\n<h2>Оглавление</h2>\n\n{% include posts.html %}\n"
  }
]