text:
@page Features
@parent DoneJS
@hide sidebar
@outline 2 ol

@description

Learn about the features that will help you get your app done.

### All-in-one stack

DoneJS offers everything you need to build a modern web app. It comes with a module loader, build system, MVVM utilities, full testing layer, documentation generator, server side rendering utilities, a data layer, and more. Its completeness is itself a feature.

There's no mixing and matching pieces of your stack. Just `npm install` and get started.

Choosing a modern stack is not at all simple or straightforward.

1. *What types of tools do you want?*   Server-side rendering? What is a virtual DOM? Do I need one? MVVM or Flux? Should I set up testing infrastructure? Documentation?

2. *Choose all your pieces.* The good news is, you have [many choices](http://microjs.com/#). The bad news is, you have many choices. React, Angular, or Vue? WebPack, rollup, or parcel? Mocha or QUnit? What tool will run my tests?

3. *Finally, you have to make sure your chosen tools work together effectively.* Does parcel work well with Angular? Does Karma work with Browserify? What about React and Babel?

DoneJS gives you a full solution. It's our mission to eliminate any ambiguity around choosing technology for building an app, so you spend less time tinkering with your stack, and more time actually building your app.

And as we've proven [over the last 8 years](./About.html#evolve), we'll keep updating the stack as the state of the art evolves over time.

### Integrated layers

Just like Apple integrates the hardware and software for its devices, DoneJS integrates different technologies in a way that creates unique advantages that you can only get from using an integrated solution.

#### Cross-layer features

DoneJS makes it easier to do things that are not possible, or at best DIY, with competitor frameworks, by spanning technology layers. Here are a couple examples:

##### 1. [Server-side rendering](#server-side-rendered)

Server-side rendering (SSR), which you can read about in more detail in its [section](#server-side-rendered) below, spans many layers to make setup and integration simple.

It uses [zones](https://davidwalsh.name/can-zone) to automatically notify the server to delay rendering, [hot module swapping](#hot-module-swapping) automatically integrates (no need to restart the server while developing), data is cached on the server and pushed to the client (http/2 server [PUSH](https://www.smashingmagazine.com/2017/04/guide-http2-server-push/) or [Preload Links](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content) for http/1.1) automatically and used to prevent duplicate AJAX requests. Support for these features is only possible because of code that spans layers, including can-zone, done-ssr, CanJS, and StealJS.

By contrast, React supports SSR, but you're left to your own devices to support delaying rendering, hot module swapping, and request reuse.

##### 2. [Progressive enhancement](#how-it-works-1)

Parts of your application can be progressively loaded using [steal.import](https://stealjs.com/docs/steal.import.html):

```js
import { DefineMap } from "can";

export default DefineMap.extend("AppViewModel", {
  page: "string",
  get pageComponent() {
    let moduleName = `~/pages/${this.page}/`;
    let Component = (await steal.import(moduleName)).default;
    return new Component();
  }
})
```

and then running `donejs build`.

DoneJS' generators define anything within `~/pages` to be split into bundles. This feature spans StealJS, steal-tools, and donejs-cli.

#### Story-level solutions

Another advantage of the integration between DoneJS' parts is the ability to solve development problems on the level of [**stories**](http://searchsoftwarequality.techtarget.com/definition/user-story) rather than just features.

Solving a story means a packaged solution to a development problem, where several features across layers converge to solve the problem from start to finish. Here are several examples of stories that DoneJS solves:

1. [Modular workflow](#modular-workflow) - DoneJS makes it possible for teams to design and share components easily. Starting with [generators](#generators), users can create [modlets](#modlets) that encapsulate everything a [custom element](#custom-html-elements) needs, easily add [documentation](#documentation) and [testing](#comprehensive-testing), then use [npm import and export](#npm-packages) to easily share the modules with other developers, no matter what module format they're using.

2. [Performance](#performance-features) - DoneJS was designed from the start to solve the performance story, packaging [server-side rendering](#server-side-rendered), [progressive loading](#progressive-loading), [worker thread rendering](#worker-thread-rendering), [data layer caching](#caching-and-minimal-data-requests), and more, all under one roof.

3. [Maintainability](#maintainability-features) - [testing](#comprehensive-testing), [docs](#documentation), [MVVM](#mvvm-architecture)

4.  Developer efficiency - [zero-config npm imports](#npm-packages), [hot module swapping](#hot-module-swapping), [ES6 support](#es6-modules)

### Feature comparison

SOLUTION LEGEND

EASY

GOOD

DIFFICULT

THIRD-PARTY

NO

          FEATURES

Server-Side Rendering

              <div class="has-popover" data-toggle="popover" data-placement="bottom" data-html="true" data-content="Requires some manual setup." title="Requires some manual setup.">

              <div class="has-popover" data-container="matrix-wrapper" data-toggle="popover" data-placement="bottom" data-html="true" data-content="Requires some manual setup and lacks most of the features/support DoneJS has." title="Requires some manual setup and lacks most of the features/support DoneJS has.">

Progressive Dependency Loading

Caching & Minimal Data Requests

Minimal DOM Updates

Worker Thread Rendering

Deploy to a CDN

iOS, Android, and Desktop Builds

Browser Support

Real-Time

Pretty URLs

Comprehensive Testing

Documentation

Continuous Integration & Deployment

npm Packages - Imports & Exports

ES6 modules

Custom HTML Elements

MVVM Architecture

Hot Module Swapping

Generators

@body

## Performance Features

DoneJS is configured for maximum performance right out of the box.

### Server-Side Rendered

DoneJS applications are written as [Single Page Applications](https://en.wikipedia.org/wiki/Single-page_application),
and are able to be rendered on the server by running the same code. This is known as [Isomorphic JavaScript](http://isomorphic.net/javascript), or [Universal JavaScript](https://medium.com/@mjackson/universal-javascript-4761051b7ae9).

Server-side rendering (SSR) provides two large benefits over traditional single page apps: much better page load performance and SEO support.

SSR apps return fully rendered HTML. Traditional single page apps return a page with a spinner. The benefit to your users is a noticeable difference in perceived page load performance:

Compared to other server-side rendering systems, which require additional code and infrastructure to work correctly, DoneJS is uniquely designed to make turning on SSR quick and easy, and the server it runs is lightweight and fast.

#### SEO

Search engines can't easily index SPAs. Server-side rendering fixes that problem entirely. Even if [Google can understand some JavaScript now](http://googlewebmastercentral.blogspot.ca/2014/05/understanding-web-pages-better.html), many other search engines cannot.

Since search engines see the HTML that your server returns (if you want search engines to find your pages) you'll want Google and other search engines seeing fully rendered content, not the spinners that normally show after initial SPAs load.

#### How it works

DoneJS implements SSR with a single-context virtual DOM utilizing [zones](https://davidwalsh.name/can-zone).

**Single context** means every request to the server reuses the same context: including memory, modules, and even the same instance of the application.

**Virtual DOM** means a virtual representation of the DOM: the fundamental browser APIs that manipulate the DOM, but stubbed out.

A **zone** is used to isolate the asynchronous activity of one request. Asynchronous activity like API requests are *tracked* and DoneJS' SSR will wait for all to complete, ensuring that the page is fully rendered before showing HTML to the user.

When using DoneJS SSR, the same app that runs on the client is loaded in Node. When a request comes in:
 1. The server handles the incoming request by reusing the application that is already running in memory. It doesn't reload the application which means the initial response is very fast.
 1. The app renders content the same way it would in the browser, but with a mocked out virtual DOM, which is much faster than a real DOM.
 1. The server creates a new zone to wait for all your asynchronous data requests to finish before signaling that rendering is complete.
 1. When rendering is complete, the virtual DOM renders the string representation of the DOM, which is sent back to the client.

Since SSR produces fully rendered HTML, it's possible to insert a caching layer, or use a service like Akamai, to serve most requests. Traditional SPAs don't have this option.

Rather than a virtual DOM, some other SSR systems use a headless browser on the server, like PhantomJS, which uses a real DOM. These systems are much slower and require much more intensive server resources.

Some systems, even if they do use a virtual DOM, require a new browser instance entirely, or at the very least, reloading the application and its memory for each incoming request, which also is slower and more resource intensive than DoneJS SSR.

##### Prepping your app for SSR

Any app that is rendered on the server needs a way to notify the server that any pending asynchronous data requests are finished, and the app can be rendered.

React and other frameworks that support SSR don't provide much in the way of solving this problem. You're left to your own devices to check when all asynchronous data requests are done, and delay rendering.

In a DoneJS application, asynchronous data requests are tracked automatically. Using can-zone, DoneJS keeps a count of requests that are made and waits for all of them to complete.

View the Documentation
View the Guide

_Server-side rendering is a feature of [done-ssr](https://github.com/donejs/done-ssr)_

### Incremental Rendering

DoneJS applications by default employ [incremental rendering](https://www.bitovi.com/blog/utilizing-http2-push-in-a-single-page-application) to get the best possible load performance. If SEO is important go for [Server-side rendering](#server-side-rendered) instead.

Incrementally rendering apps return an initial HTML that includes the *skeleton* of your application and a tiny runtime script that connects *back* to the server to receive and apply incremental rendering instructions.

#### How it works

Incremental rendering uses most of the same mechanisms as server-side rendering in DoneJS: the single context virtual DOM provided by done-ssr, zones using can-zone.

What makes incremental rendering different is that it gets an initial page to the user as quickly as possible, while it *continues to render*. Any changes that take place on the server after HTML is sent get streamed as mutation instructions back to the browser where they are reapplied.

1. Like with SSR, the server reuses the existing application context and renders the requested route.
1. Once the page skeleton is ready the HTML is sent back to the browser. Along with the HTML is a small script that makes a request back to the server like `_donessr_instructions/uniqueId`.
1. These instructions are PUSHed with http/2 or preloaded with http/1.
1. Back on the server, the app continues to render as data requests are completed and other asynchronous activity takes place.
1. The script connects using [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) and applies the DOM mutations that are streamed from the server.
1. Meanwhile the *application begins to run in the client* the same way it would in any Single-page Application.
1. The embedded script detects when the client-side application catches up to the mutations and __flips__ so that the app is shown.

### Progressive Loading

When you first load a single page app, you're typically downloading all the JavaScript and CSS for every part of the application. These kilobytes of extra weight slow down page load performance, especially on mobile devices.

DoneJS applications load only the JavaScript and CSS they need, when they need it, in highly optimized and cacheable bundles. That means your application will load *fast*.

There is no configuration needed to enable this feature, and wiring up progressively loaded sections of your app is simple.

#### How it works

Other build tools require you to manually configure bundles, which doesn't scale with large applications.

In a DoneJS application any components (either modlets or `.component` files) contained within the `~/pages` folder are progressively loaded.

Then you run the build.

```
donejs build
```

A build time algorithm analyzes the application's dependencies and groups them into bundles, optimizing for minimal download size.

That's it! No need for additional configuration in your JavaScript.

View the Documentation
View the Guide

_Progressive Loading is a feature of [StealJS](https://stealjs.com/) with additional support via the [`<can-import>` tag](https://canjs.com/docs/can%7Cview%7Cstache%7Csystem.import.html) of [CanJS](https://canjs.com/)_

### Caching and Minimal Data Requests

DoneJS improves performance by intelligently managing the data layer, taking advantage of various forms of caching and request reduction techniques.

Undoubtedly, the slowest part of any web application is round trips to the server. Especially now that [more than 50% of web traffic comes from mobile devices](http://searchengineland.com/its-official-google-says-more-searches-now-on-mobile-than-on-desktop-220369), where connections are notoriously slow and unreliable, applications must be smart about reducing network requests.

Making matters worse, the concerns of maintainable architecture in single page applications are at odds with the concerns of minimizing network requests. This is because independent, isolated UI widgets, while easier to maintain, often make AJAX requests on page load. Without a layer that intelligently manages those requests, this architecture leads to too many AJAX requests before the user sees something useful.

With DoneJS, you don't have to choose between maintainability and performance.

DoneJS uses the following strategies to improve perceived performance (reduce the amount of time before users see content rendered):

 - [Fall through caching](#fall-through-caching) - Cache data in localStorage. Automatically show cached data immediately, but look for updates on the server in the background and merge changes.
 - [Combining requests](#combining-requests) - Instead of making multiple, independent requests to the same API, combine them into a single request.
 - [Request caching](#request-caching) - Reduce the number and size of server requests by intelligently using cached datasets.
 - [Inline cache](#inline-cache) - Use data embedded in the page response instead of making duplicate requests.

#### How it works

[can-connect](https://canjs.com/doc/can-connect.html) makes up part of the DoneJS model layer. Since all requests flow through this data layer, by making heavy use of set logic and localStorage caching, it's able to identify cache hits, even partial hits, and make the most minimal set of requests possible.

It acts as a central hub for data requests, making decisions about how to best serve each request, but abstracting this complexity away from the application code. This leaves the UI components themselves able to make requests independently, and with little thought to performance, without actually creating a poorly performing application.

##### Fall through caching

Fall through caching serves cached data first, but still makes API requests to check for changes.

The major benefit of this technique is improved perceived performance. Users will see content faster. Most of the time, when there is a cache hit, that content will still be accurate, or at least mostly accurate.

This benefits two types of situations. First is page loads after the first page load (the first page load populates the cache). This scenario is less relevant when using server-side rendering. Second is long-lived applications that make API requests after the page has loaded. These types of applications will enjoy improved performance.

By default, this is turned on, but can easily be deactivated for data that should not be cached.

Here's how the caching logic works:

1. When the application loads, it checks for available cache connections.
1. When a request is made, it checks for a cache hit.
1. If there is a hit, the request is completed immediately with the cached data.
1. Regardless of a hit or miss, a request is made in the background to the actual API endpoint.
1. When that response comes back, if there was a difference between the API response data and the cache hit data, the initial request promise's data is updated with the new data. Template data bindings will cause the UI to update automatically with these changes.
1. Updated response data is automatically saved in the cache, to be used for future requests - whether that's in the current page session, or when the user comes back in the future.

<video style="width:100%;" controls poster="static/img/poster-fall-thru-caching.jpg" preload="none">
    <source src="static/img/donejs-fallthrough-caching.webm" type="video/webm">
    <source src="static/img/donejs-fallthrough-caching.ogg" type="video/ogg">
    <source src="static/img/donejs-fallthrough-caching.mp4" type="video/mp4">
</video>

##### Combining requests

Combining requests combines multiple incoming requests into one, if possible. This is done with the help of [set algebra](https://en.wikipedia.org/wiki/Algebra_of_sets).

DoneJS collects requests that are made within a few milliseconds of each other, and if they are pointed at the same API, tries to combine them into a single superset request.

For example, the video below shows an application that shows two filtered lists of data on page load - a list of completed and incomplete todos. Both are subsets of a larger set of data - the entire list of todos.

Combining these into a single request reduces the number of requests. This optimization is abstracted away from the application code that made the original request.

<video style="width:100%;" controls poster="static/img/poster-combine-requests.jpg" preload="none">
    <source src="static/img/donejs-combine-requests.webm" type="video/webm">
    <source src="static/img/donejs-combine-requests.ogg" type="video/ogg">
    <source src="static/img/donejs-combine-requests.mp4" type="video/mp4">
</video>

##### Request caching

Request caching is a type of caching that is more aggressive than fallthrough caching. It is meant for data that doesn't change very often. Its advantage is it reduces both the number of requests that are made, and the size of those requests.

There are two differences between request and fallthrough caching:

1. Cached data is not invalidated.

Once data is in the cache, no more requests to the API for that same set of data are made. You can write code that invalidates the cache at certain times, or after a new build is released.

2. The smallest possible request is made, based on the contents of the cache, and merged into a complete result set.

The request logic is more aggressive in its attempts to find subsets of the data within the cache, and to only make an API request for the subset NOT found in the cache. In other words, partial cache hits are supported.

The video below shows two example scenarios. The first shows the cache containing a superset of the request. The second shows the cache containing a subset of the request.

<video style="width:100%;" controls poster="static/img/poster-request-caching.jpg" preload="none">
    <source src="static/img/donejs-request-caching.webm" type="video/webm">
    <source src="static/img/donejs-request-caching.ogg" type="video/ogg">
    <source src="static/img/donejs-request-caching.mp4" type="video/mp4">
</video>

##### Inline cache and server push

Server-side rendered single page apps (SPAs) have a problem with wasteful duplicate requests. These can cause the browser to slow down, waste bandwidth, and reduce perceived performance.

1. When a page is rendered server-side, it makes data requests on the server to various APIs.
1. After the page's rendered HTML loads in the client, the SPA is loaded in the client, so that subsequent requests are handled within the SPA.
1. The SPA will want to re-request for the same data that was already requested on the server.

DoneJS solves this problem with server push and an inline cache - embedded inline JSON data sent back with the server rendered content, which is used to serve the initial SPA data requests.

DoneJS uniquely makes populating and using the inline cache easy. Using plain XHR:

1. Tells the SSR server to wait for a promise to resolve before rendering.
1. Collects data from each promise and uses it to populate the inline cache. In http/2 servers it does a server PUSH instead, which elimnates the need for inlining the data in HTML.

For example:

```js
Component.extend({
  tag: "user-name",
  view: `{{user.name}}`,
  ViewModel: {
    id: "number",
    get userPromise() {
      return User.get({ id: this.id });
    }
  }
});
```

The model layer seamlessly integrates the inline cache in client side requests, without any special configuration.

While this flow would be possible in other SSR systems, it would require manually setting up all of these steps.

This video illustrates how it works.

<video style="width:100%;" controls poster="static/img/poster-inline-cach.jpg" preload="none">
    <source src="static/img/donejs-inline-cache.webm" type="video/webm">
    <source src="static/img/donejs-inline-cache.ogg" type="video/ogg">
    <source src="static/img/donejs-inline-cache.mp4" type="video/mp4">
</video>

View the Documentation
View the Guide

_Caching and minimal data requests is a feature of [can-connect](https://github.com/canjs/can-connect)_

### Minimal DOM Updates

The rise of templates, data binding, and MV* separation, while boosting maintainability, has come at the cost of performance. Many frameworks are not careful or smart with DOM updates, leading to performance problems as apps scale in complexity and data size.

DoneJS' view engine touches the DOM more minimally and specifically than competitor frameworks, providing better performance in large apps and a "closer to the metal" feel.

Take the TodoMVC application as an example. If you measure how long it takes DoneJS and React to render the same number of todos you'll see the performance advantage of minimal DOM updates. In fact, we did just that and here's the result:

_For a small set of todos the difference is negligible but as the number increases the gap widens to the point where React is 6 times slower than DoneJS when rendering 1000 todos._

You can run this test for yourself at JS Bin.

#### How it works

Consider the following template:

```html
{{#for(row of this.rows)}}
<div>{{row.name}}</div>
{{/for}}
```

And the following change to its data:

```js
rows[0].name = 'changed'; // change the first row's name
```

In DoneJS, which uses the [can-stache](https://canjs.com/doc/can-stache.html) view engine, that would:

 1. Trigger an event (because of the [DefineMap](https://canjs.com/doc/can-define/map/map.html) object observe API)
 1. The event invokes a data binding event handler in the template layer
 1. The handler immediately results in the following code being run:
```js
textNode.nodeValue = 'changed';
```

In Backbone, you would need to manually re-render the template or roll your own rendering library.

In Angular, at the end of the current $digest cycle, that would result in an expensive comparison between the old rows array and the new one to see what properties have changed. After the changed property is discovered, the specific DOM node would be updated.

In React, that would result in the virtual DOM being re-rendered. A diff algorithm comparing the new and old virtual DOM would discover the changed node, and then the specific DOM node would be updated.

Of these four approaches, DoneJS knows about the change the quickest, and updates the DOM the most minimally.

To see this in action run the test embedded below that shows how DoneJS, React and Angular compare when updating the DOM when a single property changes:

You can run this test yourself at JS Bin

With synchronously observable objects and data bindings that change minimal pieces of the DOM, DoneJS aims to provide the best possible mix between powerful, yet performant, templates.

can-stache Documentation
DefineMap Documentation

_Minimal DOM updates is a feature of [CanJS](https://canjs.com/)_

### Memory Safety

Preventing memory leaks is a critical feature of any client-side framework. The biggest source of memory leaks in client-side applications is event handlers. When adding an event handler to a DOM node you have to be sure to remove that handler when the node is removed. If you do not, that DOM node will never be garbage collected by the browser.

#### How it works

When event listeners are created in a DoneJS application using template event binding or by binding using Controls, internally these handlers are stored. This looks like:

```html
<a href="/todos/new" on:click="this.newTodo()">New Todo</a>
```

Internally CanJS listens for this element's "removed" event. The "removed" event is a synthetic event that will be used to:

* Remove all event listeners.
* Remove DOM data associated with the element.
* Remove any template bindings, such as computes bound to text within the template.

CanJS is different from other frameworks in that it will clean up its own memory event when not using the framework to tear down DOM. For example, if you were to do:

```js
todoAnchor.parentNode.removeChild(todoAnchor);
```

The event listener created would still be torn down. This is because CanJS uses a [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to know about all changes to the DOM. When it sees an element was removed it will trigger the "removed" event, cleaning up the memory.

### Deploy to a CDN

DoneJS makes it simple to deploy your static assets to a CDN (content delivery network).

CDNs are distributed networks of servers that serve static assets (CSS, JS, and image files). You only push your files to one service, and the CDN takes care of pushing and updating your assets on different servers across the country and globe. As your app scales CDNs will keep up with the demand, and help support users regardless if they are in New York or Melbourne.

_Without a CDN, requests will take longer to fulfill if the user is located further away from your servers._

_With a CDN, requests can be fulfilled much quicker. Users are served content from the servers located nearest to them._

#### How it works

It's widely known that CDNs offer the best performance for static assets, but most apps don't use them, mainly because its annoying: annoying to automate, configure, and integrate with your build process.

DoneJS comes with integrations with [S3](https://aws.amazon.com/s3/) and [Firebase](https://www.firebase.com) (popular CDN services) that make configuring and deploying to a CDN dirt simple.

 1. You sign up for Firebase.
 2. You run: `donejs add firebase` in your terminal. It asks a few questions, most of which you can accept the default answer.
 3. You run `donejs deploy`.

That's it. Now when you run your server in production mode, all static assets (CSS, JS, images, etc) are served from the CDN.

Even better, you can set up [continuous deployment](./place-my-order.html#continuous-deployment), so that TravisCI or other tools will deploy your code, including pushing out your latest static files to the CDN, automatically.

View the Guide

## Usability features

DoneJS is used to make beautiful, real-time user interfaces that can be exported to run on every platform.

### iOS, Android, and Desktop Builds

Write your application once, then run it natively on every device and operating system. You can make iOS, Android, and desktop builds of your DoneJS application with no extra effort.

_Our DoneJS Chat App running as a macOS desktop app and inside an iOS emulator._

#### How it works

For iOS and Android builds, DoneJS integrates with [Apache Cordova](https://cordova.apache.org/) to generate a mobile app that is ready to be uploaded to Apple's App Store or Google Play.

For native desktop applications, DoneJS integrates with [Electron](https://electron.atom.io/) or [NW.js](https://github.com/nwjs/nw.js) to create a native macOS, Windows, or Linux application.

Adding this integration is as simple as running

```
donejs add cordova
donejs add nw
donejs add electron
donejs build
```

With these simple integrations, you can expand your potential audience without having to build separate applications.

View the Documentation
View the Guide

_Cordova, Electron, and NW.js integration are features of the [steal-electron](https://github.com/stealjs/steal-electron), [steal-cordova](https://github.com/stealjs/steal-cordova), and [steal-nw](https://github.com/stealjs/steal-nw) projects._

### Supports All Browsers, Even IE11

DoneJS applications support Internet Explorer 11 with minimal additional configuration. You can even write applications using [most ES6 features](https://babeljs.io/docs/usage/caveats/), using the built-in babel integration.

Many people won't care about this because Internet Explorer is on its way out, which is a very good thing!

But it's [not quite dead yet](https://youtu.be/grbSQ6O6kbs?t=61). For many mainstream websites, banks, and e-commerce applications, IE continues to hang around the browser stats.

And while other frameworks don't support Internet Explorer at all, DoneJS makes it easy to write one app that runs everywhere.

View the Guide

### Real Time Connected

DoneJS is designed to add real-time behavior to applications using any backend technology stack.

[Socket.io](https://socket.io) provides the basics to add real-time capabilities to any JavaScript application, but the challenge of integrating real-time updates into your code remains.

When new data arrives, how do you know what data structures to add it to? And where to re-render? Code must be written to send socket.io data across your application, but that code becomes aware of too much, and therefore is brittle and hard to maintain.

DoneJS makes weaving Socket.io backends into your UI simple and automatic.

#### How it works

DoneJS' model layer uses set logic to maintain lists of data represented by JSON properties, like a list of todos with `{'ownerId': 2}`. These lists are rendered to the UI via data bound templates.

When server-side updates are sent to the client, items are automatically removed or added to any lists they belong to. They also automatically show up in the UI because of the data bindings.

All of this happens with about 4 lines of code.

```js
const socket = io('https://chat.donejs.com');
socket.on('messages created',
  order => messageConnection.createInstance(order));
socket.on('messages updated',
  order => messageConnection.updateInstance(order));
socket.on('messages removed',
  order => messageConnection.destroyInstance(order));
```

[Follow the guide](./Guide.html#enable-a-real-time-connection) to see an example in action. View the can-connect real-time documentation [here](https://canjs.com/doc/can-connect/real-time/real-time.html).

View the Documentation
View the Guide

_Real time connections is a feature of the [can-connect](https://canjs.com/doc/can-connect.html) project._

### Pretty URLs with Pushstate

DoneJS applications use [pushstate](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method) to provide navigable, bookmarkable pages that support the back and refresh buttons, while still keeping the user on a single page.

The use of pushstate allows your apps to have "Pretty URLs" like `myapp.com/user/1234` instead of uglier hash-based URLs like `myapp.com#page=user&userId=1234` or `myapp.com/#!user/1234`.

Wiring up these pretty URLs in your code is simple and intuitive.

#### How it works

Routing works a bit differently than other libraries. In other libraries, you might declare routes and map those to controller-like actions.

DoneJS application [routes](https://canjs.com/doc/can-route.html) map URL patterns, like `/user/1`, to properties in our application state, like `{'userId': 1}`. In other words, our routes will just be a representation of the application state.

This architecture simplifies routes so that they can be managed entirely in simple data bound templates, like the following example:

```html
{{#switch page}}
  {{#case "home"}}
      <myapp-home></myapp-home>
  {{/case}}
  {{#case "users"}}
    {{#if(slug)}}
      <myapp-user-detail userId:bind="slug"></myapp-user-detail>
    {{else}}
      <myapp-users></myapp-users>
    {{/if}}
  {{/case}}
{{/switch}}
```

View the Guide

_Pretty URLs and routing are features of the [CanJS](https://canjs.com/) project._

## Maintainability features

DoneJS helps developers get things done quickly with an eye toward maintenance.

### Comprehensive Testing

Nothing increases the maintainability of an application more than good automated testing. DoneJS includes a comprehensive test layer that makes writing, running, and maintaining tests intuitive and easy.

DoneJS provides tools for the entire testing lifecycle:

* [Generators](#generators) - create boilerplate tests to get started quickly
* [Unit testing](#unit-tests) - assertion libraries to test your module interfaces
* [Functional testing](#functional-tests) - scripting the browser, simulating user actions, and testing your UI modules
* [User action event simulation](#event-simulation-accuracy) - accurate event simulation for clicks, types, drags, and other user actions
* [A command line test runner](#running-tests-from-the-command-line) - invoke the same tests from the CLI
* [A browser launcher](#running-tests-from-the-command-line) - launch several browsers and target your tests against them
* [A reporting tool](#running-tests-from-the-command-line) - report results, including code coverage, to the CLI, in various formats
* [Simple integration with continuous integration tools](#continuous-integration--deployment) - one step to hook into TravisCI or other CI systems
* [A mock layer](#mocking-server-apis) - mock out your server APIs so you can test your app in isolation from a server

    <video tabindex="0" preload="none" class="img-responsive" poster="static/img/donejs-testing.jpg">
        <source src="static/img/donejs-testing-no-fade-in.mov" type="video/mp4">
        <source src="static/img/donejs-testing-no-fade-in.mp4" type="video/mp4">
        <source src="static/img/donejs-testing-no-fade-in.ogg" type="video/mp4">
        <source src="static/img/donejs-testing-no-fade-in.webm" type="video/webm">
    </video>

#### How it works

Testing JavaScript apps is a complex task process unto itself. To do it right, you need many tools that have to work together seamlessly. DoneJS provides everything you need - the whole stack.

##### Generators

The DoneJS app generator command `donejs add app` creates a working project-level test HTML and JS file. Component generators via `donejs add component cart` create a test script and individual test page for each test.

##### Unit tests

Unit tests are used to test the interface for modules like models and view models. You can choose between BDD style unit tests with Jasmine, Mocha, or a more traditional TDD assertion style with QUnit.

##### Functional tests

Functional tests are used to test UI components by simulating user behavior. The syntax for writing functional tests is jQuery-like, chainable, and asynchronous, simulating user actions and waiting for page elements to change asynchronously.

```js
test('destroying todos', function() {
  F('#new-todo').type('Sweet. [enter]');

  F('.todo label:contains("Sweet.")').visible('basic assert');
  F('.destroy').click();

  F('.todo label:contains("Sweet.")').missing('destroyed todo');
});
```

##### Event simulation accuracy

User action methods, like click, type, and drag, simulate exactly the sequence of events generated by a browser when a user performs that action. For example this:
```js
F( ".menu" ).click();
```

is not just a click event. It triggers a mousedown, then blur, then focus, then mouseup, then click. The result is more accurate tests that catch bugs early.

Even further, there are differences between how IE and Safari handle a click. DoneJS tests take browser differences into account when running functional tests.

##### Running tests from the command line

DoneJS comes with a command line test runner, browser launcher, and reporting tool that integrates with any [continuous integration](#continuous-integration--deployment) environment.

No setup required, running a DoneJS project's test is as simple as running:

```
donejs test
```

You can run launch your unit and functional tests from the cli, either in headless browser mode, or via multiple real browsers. You can even launch browserstack virtual machines to test against any version of Android, Windows, etc.

The reporting tool gives detailed information about coverage statistics, and lets you choose from many different output formats, including XML or JSON files.

##### Mocking server APIs

Automated frontend testing is most useful when it has no external dependencies on API servers or specific sets of data. Thus a good mock layer is critical to writing resilient tests.

DoneJS apps use fixtures to emulate REST APIs. A default set of fixtures is created by generators when a new model is created. Fixtures are very flexible, and can be used to simulate error states and slow performing APIs.

```js
import fixture from 'can-fixture';

const store = fixture.store([
  { name: 'Calisota', short: 'CA' },
  { name: 'New Troy', short: 'NT'}
],{});

fixture('/api/states/{short}', store);

export default store;
```

##### Simple authoring

Several DoneJS features converge to make authoring tests extremely simple.

Because of [ES6 Module](#es6-modules) support, everything in a DoneJS app is a module, so a test can simply import the modules it needs - such as fixtures and module under test:

```js
import restaurantStore from 'place-my-order/models/fixtures/restaurant';
import { ViewModel } from './list';
```

This means the test is small, isolated, and simple. Tests themselves are modules too, so they can be collected easily into sets of tests.

Because of the [modlet](#modlets) pattern, each component contains its own working test script and test file, which can be worked on in isolation.

Because of [hot module swapping](#hot-module-swapping), you can write, debug, and run tests without constantly reloading your page.

Other frameworks require a build step before tests can be run. These builds concatenate dependencies and depend on the specific order of tests running, which is a brittle and inefficient workflow.

Because DoneJS uses a client side loader that makes it simple to start a new page that loads its own dependencies, there is no build script needed to compile and run tests.

You just run the generator, load your modules, write your test, and run it - from the browser or CLI.

You spend less time messing with test infrastructure,

...and more time mud ridin'.

##### More information

The DoneJS testing layer involves many pieces, so if you want to learn more:

 * follow along in the [Unit testing view model and fixtures](./place-my-order.html#creating-a-unit-tested-view-model) section of the guide
 * see how to run tests and set up CI automation in the [CI section](./place-my-order.html#continuous-integration) of the guide
 * read about [FuncUnit](https://funcunit.com/), the functional testing and asynchronous user action simulating library
 * read about [syn](https://github.com/bitovi/syn) - the synthetic event library
 * read about the [Testee.js](https://github.com/bitovi/testee) browser launcher, test runner, and reporting tool
 * read the [can-fixture](https://canjs.com/doc/can-fixture.html) docs

### Documentation

Documentation is critical for maintainability of any complex application. When your team adds developers, docs ensure minimal ramp up time and knowledge transfer.

Yet most teams either don't write docs, or they'll do it "later" - a utopian future period that is always just out of reach. Why? Because it's extra work to set up a tool, configure it, create and maintain separate documentation files.

DoneJS comes with a documentation tool built in, and it generates multi-versioned documentation from inline code comments. It eliminates the barrier to producing documentation, since all you have to do is comment your code (which most people already do) and run `donejs document`.

    <video tabindex="0" preload="none" class="img-responsive" poster="static/img/done-js-documentation.jpg">
        <source src="static/img/donejs-documentation-no-fade-in.mov" type="video/mp4">
        <source src="static/img/donejs-documentation-no-fade-in.mp4" type="video/mp4">
        <source src="static/img/donejs-documentation-no-fade-in.ogg" type="video/mp4">
        <source src="static/img/donejs-documentation-no-fade-in.webm" type="video/webm">
    </video>

#### How it works

You write comments above the module, method, or object that you want to document:

```js
/**
 * @module {function} utils/add
 * @parent utils
 *
 * The module's description is the first paragraph.
 *
 * The body of the module's documentation.
 *
 * @param {Number} first This param's description.
 * @param {Number} second This param's description.
 * @return {Number} This return value's description.
 */
export default function(){ ... };
```

Then run `donejs document`. A browsable documentation website will be generated.

DoneJS applications use [DocumentJS](https://documentjs.com) to produce multi-versioned documentation. It lets you:

- Write docs inline or in markdown files.
- Specify your code's behavior precisely with JSDoc and [Google Closure Compiler annotations](https://developers.google.com/closure/compiler/docs/js-for-compiler?hl=en) - a well-known documentation syntax.
- Customize your site's theme and layout.
- Generate multi-versioned documentation.
- Document CSS alongside JavaScript. You can even make a [live style guide](https://documentjs.com/examples/styles/index.html).

You can keep it simple like the example above, or you can customize your docs with many powerful features. In fact, this entire site and the [CanJS](https://canjs.com/doc/api.html) site are generated using DocumentJS.

You spend less time messing with Documentation generators,

...and more time perfecting your moonwalk.

View the Documentation
View the Guide

_DoneJS Documentation is a feature of [DocumentJS](https://documentjs.com/)_

### Continuous Integration & Deployment

Continuous Integration (CI) and Continuous Deployment (CD) are must have tools for any modern development team.

CI is a practice whereby all active development (i.e. a pull request) is checked against automated tests and builds, allowing problems to be detected early (before merging the code into the release branch).

_Example of a GitHub pull request with Travis CI integrated. Warns users in advance of merges if their changes will break builds or fail tests._

CD means that any release or merges to your release branch will trigger tests, builds, and deployment.

Paired together, CI and CD enable automatic, frequent releases. CD isn't possible without CI. Good automated testing is a must to provide the confidence to release without introducing bugs.

DoneJS provides support for simple integration into popular CI and CD tools, like TravisCI and Jenkins.

    <video tabindex="0" preload="none" class="img-responsive" poster="static/img/continuous-integration0deployment.jpg">
        <source src="static/img/donejs-continuous-integration0deployment-no-fade-in.mov" type="video/mp4">
        <source src="static/img/donejs-continuous-integration0deployment-no-fade-in.mp4" type="video/mp4">
        <source src="static/img/donejs-continuous-integration0deployment-no-fade-in.ogg" type="video/mp4">
        <source src="static/img/donejs-continuous-integration0deployment-no-fade-in.webm" type="video/webm">
    </video>

#### How it works

Setting up continuous integration and deployment involves several steps:
 1. Writing tests
 1. Setting up a test harness that runs tests from the command line
 1. Creating simple scripts for running a build, test, and deploy
 1. Integrating with a service that runs the scripts at the proper times

Steps 1, 2, and 3 are the hard parts. Step 4 is simple. DoneJS supports  in two main ways: proper test support and simple CLI commands.

##### Proper test support

DoneJS comes with comprehensive support for testing. The [Testing](#comprehensive-testing) section contains much more detail about testing support.

[Generators](#generators) create working test scripts right off the bat, and the plumbing for test automation is built into each project. Each [modlet](#modlets) contains a skeleton for unit tests. All that is left for the developer to do is write tests.

##### Simple CLI commands

Another hurdle is creating automated build, test, and deployment scripts. Every DoneJS app comes with a build, test, and deployment one-liner: `donejs build`, `donejs test`, and `donejs deploy`.

##### Tool integration

Once the tests are written and the scripts are automated, integrating with the tools that automatically runs these scripts is quite simple. For instance, setting up Travis CI involves signing up and adding a `.travis.yml` file to the project:

```
language: node_js
node_js: node
script: npm start & npm test
before_install:
  - "export DISPLAY=:99.0"
  - "sh -e /etc/init.d/xvfb start"
```

View the CI Guide
View the CD Guide

### Modlets

The secret to building large apps is to never build large apps. Break up your application into small pieces. Then, assemble.

DoneJS encourages the use of the modlet file organization pattern. Modlets are small, decoupled, reusable, testable mini applications.

#### How it works

Large apps have a lot of files. There are two ways to organize them: by type or by module.

Organization by module - or modlets - make large applications easier to maintain by encouraging good architecture patterns. The benefits include:

 * Each modlet contains its own demo page and its own test page. Getting a demo page running forces separation of concerns and isolated modules - hallmarks of good design. A standalone demo and test page makes it easy to work on pieces of your application in isolation.
 * Developers are more likely to update tests and documentation if they are sitting right next to the module they are editing. The test is not hidden in a `tests` folder that is more easily ignored.
 * You can develop the application without having to load the entire application and all of its tests on every change.

An example modlet from the [in-depth guide](./place-my-order.html) is the [order/new](https://github.com/donejs/place-my-order/tree/master/src/restaurant/list) component. It has its own [demo page](http://www.place-my-order.com/src/order/new/demo.html) and [test page](http://www.place-my-order.com/src/order/new/test.html).

DoneJS generators create modlets to get you started quickly. To learn more about the modlet pattern, read this [blog post](http://blog.bitovi.com/modlet-workflows/).

View the Video
View the Guide

_Modlets are a feature of DoneJS [generators](#generators)._

### npm Packages

DoneJS makes it easy to share and consume modules via package managers like npm and Bower.

You can import modules from any package manager in any format - CommonJS, AMD, or ES6 - without any configuration. And you can convert modules to any other format.

The goal of these features is to transform project workflows, making it easier to share and reuse ideas and modules of functionality across applications, with less hassle.

    <video tabindex="0" preload="none" class="img-responsive" poster="static/img/donejs-npm-packaging-custom-elements.jpg">
        <source src="static/img/donejs-npm-packaging-custom-elements-no-fade-in.mov" type="video/mp4">
        <source src="static/img/donejs-npm-packaging-custom-elements-no-fade-in.mp4" type="video/mp4">
        <source src="static/img/donejs-npm-packaging-custom-elements-no-fade-in.ogg" type="video/mp4">
        <source src="static/img/donejs-npm-packaging-custom-elements-no-fade-in.webm" type="video/webm">
    </video>

#### How it works

DoneJS apps use [StealJS](https://stealjs.com/) to load modules and install packages. This video introduces npm import and export in StealJS:

##### Zero config package installation

Unlike Browserify or Webpack, StealJS is a client side loader, so you don't have to run a build to load pages.

Installing a package in a DoneJS app via npm or bower involves no configuration. Install your package from the command line:

```
npm install jquery --save
```

Then immediately consume that package (and its dependencies) in your app:

```js
import $ from "jquery";
```

Using require.js or other client side loaders, you'd have to add pathing and other information to your configuration file before being able to use your package. In DoneJS, this step is bypassed because of scripts that add config to your package.json file as the package is installed.

You can import that package in any format: CommonJS, AMD, or ES6 module format.

##### Convert to any format

DoneJS supports converting a module to any other format: CommonJS, AMD, or ES6 module format, or script and link tags.

The advantage is that you can publish your module to a wider audience of users. Anyone writing JavaScript can use your module, regardless of which script loader they are using (or if they aren't using a script loader).

Just create an [export script](https://stealjs.com/docs/steal-tools.export.html) that points to the output formats you want, along with some options:
```js
var stealTools = require("steal-tools");
stealTools.export({
  system: {
    config: __dirname+"/package.json!npm"
  },
  outputs: {
    amd: {
      format: "amd",
      graphs: true,
      dest: __dirname + "/dist/amd"
    }
});
```

and run it from your command line:
```
node myexport.js
```

##### Modular workflow

In combination with other DoneJS features, npm module import and export make it possible for teams to design and share components easily.

[Generators](#generators) make it easy to bootstrap new modules of functionality quickly, and the [modlet pattern](#modlets) makes it easy to organize small, self-contained modules. It's even easy to create tests and documentation for each module.

DoneJS enables a modular workflow, where pieces of small, reusable functionality can be easily created, shared, and consumed.

 1. Use generators to create a modlet
 1. Develop rich functionality
 1. Write tests and docs
 1. Export and publish it - internally or externally
 1. Consume it across applications

Similar to the way that the [microservices](http://microservices.io/patterns/microservices.html) architecture encourages reuse of APIs across applications, the modular workflow encourages reuse of self-contained modules of JavaScript across applications.

Imagine an organization where every app is broken into many reusable pieces, each of which is independently tested, developed, and shared. Over time, developers would be able to quickly spin up new applications, reusing previous functionality. DoneJS makes this a real possibility.

View the Documentation
View the Guide

_npm package support is a feature of [StealJS](https://stealjs.com/)_

### ES6 Modules

DoneJS supports the compact and powerful [ES6 module](http://www.2ality.com/2014/09/es6-modules-final.html) syntax, even for browsers that don't support it yet. Besides future proofing your application, writing ES6 modules makes it easier to write modular, maintainable code.

````js
import { add, subtract } from "math";

export function subtract(a, b) {
  return a - b;
}
````

#### How it works

DoneJS applications are actually able to import or export any module type: ES6, AMD and CommonJS. This means you can slowly phase in ES6, while still using your old code. You can also use any of the many exciting [ES6 language features](https://github.com/lukehoban/es6features).

A compiler is used to convert ES6 syntax to ES5 in browsers that don't yet support ES6. During development, the compiler runs in the browser, so changes are happening live without a build step. During the build, your code is compiled to ES5, so your production code will run natively in every browser. You can even run your [ES6 application in IE11+](#supports-all-browsers-even-ie11)!

View the Documentation
View the Guide

_Pretty URLs and routing are features of the [stealjs/transpile](https://github.com/stealjs/transpile) project._

### Custom HTML Elements

One of the most important concepts in DoneJS is splitting up your application functionality into independent, isolated, reusable custom HTML elements.

The major advantages of building applications based on custom HTML elements are:

 1. **Ease of page composition** - Designers can do it! Non-developers can express complex behavior with little to no JavaScript required. All you need to build a new page or feature is HTML.
 1. **Forced modularity** - Because the nature of HTML, elements are isolated modules, custom HTML elements must be designed as small, isolated components. This makes them easier to test, debug, and understand.
 1. **Reuse** - Custom elements are designed to be reusable across pages and applications.

Just like HTML's natural advantages, composing entire applications from HTML building blocks allows for powerful and easy expression of dynamic behavior.

#### How it works

First, it's important to understand the background of custom elements and their advantages. Then, we'll discuss the details of creating powerful custom elements in specifically DoneJS, and why they're special.

##### Benefits of custom elements

Before custom HTML elements existed, to add a datepicker to your page, you would:

 1. Load a datepicker script
 1. Add a placeholder HTML element

```html
<div class='datepicker' />
```
 3. Add JavaScript code to instantiate your datepicker

```js
$('.datepicker').datepicker()
```
 4. Gather your stone tipped spears and forage for small animals to feed your family for the night.

With custom HTML elements, to add the same datepicker, you would:

 1. Load a datepicker script
 1. Add the datepicker to your HTML or template:

```html
<datepicker value:bind="date"/>
```

That might seem like a subtle difference, but it is actually a major step forward. The custom HTML element syntax allows for instantiation, configuration, and location, all happening at the same time.

Custom HTML elements are another name for [Web Components](http://webcomponents.org/), a browser spec that has [been implemented](http://caniuse.com/#search=components) across browsers.

##### Benefits of DoneJS custom elements

DoneJS uses CanJS' [can-component](https://canjs.com/doc/can-component.html) to provide a modern take on web components.

Components in DoneJS have three basic building blocks:

 * a template
 * a viewModel object
 * event handlers

There are several unique benefits to DoneJS custom elements:

 * [Easily construct custom elements](#defining-a-custom-element) - you can define them within a single `.component` file, or a modlet
 * [Load data from custom elements](#data-elements--visual-elements--expressive-templates)
 * [Simple progressive loading with can-import](#in-template-dependency-declarations)

##### Defining a custom element

One way to define a component is using a [DoneJS component](https://github.com/donejs/done-component) style declaration, using a single-file with a `.component` extension:

```html
<can-component tag="hello-world">
  <style type="less">
    i {
      color: red;
    }
  </style>
  <view>
    {{#if(this.visible)}}<b>{{this.message}}</b>{{else}}<i>Click me</i>{{/if}}
  </view>
  <script type="view-model">
    import { DefineMap } from "can";

    export default DefineMap.extend({
      visible: { default: true },
      message: { default: "Hello There!" }
    });
  </script>
  <script type="events">
    export default {
      click: function(){
        this.viewModel.visible = !this.viewModel.visible;
      }
    };
  </script>
</can-component>
```

This simple form of custom elements is great for quick, small widgets, since everything is contained in one place.

Another way to organize a custom element is a [modlet](#modlets) style file structure: a folder with the element broken into several independent pieces. In this pattern, the custom element's ViewModel, styles, template, event handlers, demo page, tests, and test page are all located in separate files. This type of custom element is well suited for [export and reuse](#modular-workflow).

DoneJS [Generators](#generators) will create both of these types of custom elements so you can get started quickly.

##### Data elements + visual elements = expressive templates

The beauty and power of custom HTML elements are most apparent when visual widgets (like graphing) is combined with elements that express data.

##### Custom element libraries

Custom elements are designed to be easily shareable across your organization. DoneJS provides support for simple [npm import and export](#npm-packages) and creating [documentation](#documentation) for elements. Together with custom element support, these features make it easier than ever to create reusable bits of functionality and share them.

Some open source examples of DoneJS custom elements:

bit-c3
bit-tabs
bit-autocomplete

Check out [their source](https://github.com/bitovi-components/bit-tabs) for good examples of shareable, documented, and tested custom elements.

##### In-template dependency declarations

[can-import](https://canjs.com/docs/can%7Cview%7Cstache%7Csystem.import.html) is a powerful feature that allows templates to be entirely self-sufficient. You can load custom elements, helpers, and other modules straight from a template file like:

```html
<can-import from="components/my_tabs"/>
<can-import from="helpers/prettyDate"/>
<my-tabs>
  <my-panel title="{{prettyDate(start)}}">...</my-panel>
  <my-panel title="{{prettyDate(end)}}">...</my-panel>
</my-tabs>
```

View the Documentation
View the Guide

_Custom HTML elements are a feature of [CanJS](https://canjs.com/)_

### MVVM Architecture

DoneJS applications employ a [Model-View-ViewModel](https://en.wikipedia.org/wiki/Model_View_ViewModel) architecture pattern, provided by [CanJS](https://canjs.com/).

The introduction of a strong ViewModel has some key advantages for maintaining large applications:

 * **Decouples the presentation from its business logic** - A ViewModel is essentially an object and methods representing the state of a View. This separation of concerns enables simple, dumb HTML-based Views containing minimal logic, while the ViewModel manages the complexities of application logic.
 * **Enables designer/developer cooperation** - Because the view is stripped of code and application logic, designers can safely and comfortably change the View without fear of breaking things.
 * **Enables easier [testing](#section=section_ComprehensiveTesting)** - ViewModels can be unit tested easily. Because they represent the view's state without any knowledge of the DOM, they provide a simple interface for testing.

#### How it works

The following video introduces MVVM in DoneJS, focusing on the strength of the ViewModel with an example.

DoneJS has a uniquely strong ViewModel layer compared to other frameworks. We'll discuss how it works and compares it to other frameworks.

##### MVVM overview

**Models** in DoneJS are responsible for loading data from the server. They can be reused across ViewModels. They often perform data validation and sanitization logic. Their main function is to represent data sent back from a server. Models use an intelligent set logic that enables [real-time](#real-time-connected) integration and [caching](#caching-and-minimal-data-requests) techniques.

**Views** in DoneJS are templates. Specifically, templates that use handlebars syntax, but with data bindings and rewritten for better performance. Handlebars templates are designed to be logic-less.

**ViewModels** will be covered in detail below.

##### Independent ViewModels

The first reason DoneJS ViewModels are unique is their independence. ViewModels and Views are completely decoupled, and can be developed completely isolated from a template.

For example, here's a typical ViewModel, which is often defined in its own separate file like `viewmodel.js` and exported as its own module:

```js
export const ViewModel = DefineMap.extend("FullNameViewModel", {
  first: "string",
  last: "string",
  get fullName() {
    return this.first + " " + this.last;
  }
})
```

The template (view) lives in its own file, so a designer could easily modify it without touching any JavaScript. This template renders the ViewModel property from above:

```html
<div>{{fullName}}</div>
```

A [custom HTML element](#custom-html-elements), also known as a component, would be used to tie these layers together:

```html
import { Component } from 'can';
import ViewModel from "./viewmodel";
import view from './view.stache';

Component.extend({
  tag: 'my-component',
  viewModel,
  view
});
```

The ViewModel is defined as its own module and exported as an ES6 module, so it can be imported into a unit test, instantiated, and tested in isolation from the DOM:

```js
import ViewModel from "./viewmodel";

QUnit.test('fullName works', function() {
  var vm = new ViewModel();
  vm.first = John;
  vm.last = Doe;
  QUnit.equal(vm.fullName, 'John Doe');
});
```

In other frameworks, ViewModels don't enjoy this level of independence. Every React class has a render function, which is essentially a template, so the View, ViewModel, and component definition are typically part of the same module. Every Angular directive is a ViewModel. In DoneJS, separating the ViewModel, template, and custom element is encouraged, making each module more decoupled and easier to unit test.

##### Powerful observable data layer

A powerful observable data layer binds the layers together with very minimal code.

DoneJS supports the following features:

1. **Direct observable objects** - changes to a property in an object or array immediately and synchronously notify any event listeners.

1. **Computed properties** - ViewModels can define properties that depend on other properties, and they'll automatically recompute only when their dependent properties change.

1. **Data bound templates** - templates bind to property changes and update the DOM as needed.

In the simple ViewModel example above, `fullName`'s value depends on `first` and `last`. If something in the application changes `first`, `fullName` will recompute.

```js
export const ViewModel = DefineMap.extend({
  first: "string",
  last: "string",
  get fullName() {
    return this.first + " " + this.last;
  }
});
```

`fullName` is data bound to the view that renders it:

```html
<div>{{fullName}}</div>
```

If `first` is changed:

```js
viewModel.first = Jane;
```

`fullName` recomputes, then the DOM automatically changes to reflect the new value.

The interplay of these layers provides amazing power to developers. ViewModels express complex relationships between data, without regard to its display. Views express properties from the ViewModel, without regard to how the properties are computed. The app then comes alive with rich functionality.

Without automatic ties connecting these layers, achieving the same `fullName` functionality would require more code explicitly performing these steps. There would need to be communication between layers, removing the isolation achieved above. Any change to `first` would need to notify ViewModel's `fullName` of a change. Any change to `fullName` would need to tell the view to re-render itself. These dependencies grow and quickly lead to unmaintainable code.

In Angular, there are no direct observables. It uses dirty checking with regular JavaScript objects, which means at the end of the current $digest cycle, it will run an algorithm that determines what data has changed. This has performance drawbacks, as well as making it harder to write simple unit tests.

In React, there is no observable data layer. You could define a `fullName` like we showed above, but it would be recomputed every time `render` is called, whether or not it has changed. Though it's possible to isolate and unit test its ViewModel, it's not quite set up to make this easy.

##### More information

To learn more:

 * Models - read about [can-connect](https://canjs.com/doc/can-connect.html) and [can-define](https://canjs.com/doc/can-define.html)
 * Computed properties - read about [can-compute](https://canjs.com/doc/can-compute.html)
 * Observable data layer - read about [DefineMap](https://canjs.com/doc/can-define/map/map.html) and [DefineList](https://canjs.com/doc/can-define/list/list.html)
 * Views - read about [can-stache](https://canjs.com/doc/can-stache.html)
 * [Create a unit tested ViewModel](./place-my-order.html#creating-a-unit-tested-view-model) in the in-depth guide

_The MVVM architecture in DoneJS is provided by [CanJS](https://canjs.com/)._

### Hot Module Swapping

Getting and staying in [flow](https://en.wikipedia.org/wiki/Flow_(psychology)) is critical while writing complex apps. In DoneJS, whenever you change JavaScript, CSS, or a template file, the change is automatically reflected in your browser, without a browser refresh.

    <video tabindex="0" preload="none" class="img-responsive" poster="static/img/donejs-live-reload.jpg">
        <source src="static/img/donejs-live-reload-no-fade-in.mov" type="video/mp4">
        <source src="static/img/donejs-live-reload-no-fade-in.mp4" type="video/mp4">
        <source src="static/img/donejs-live-reload-no-fade-in.ogg" type="video/mp4">
        <source src="static/img/donejs-live-reload-no-fade-in.webm" type="video/webm">
    </video>

#### How it works

Live reload servers generally watch for file changes and force your browser window to refresh. DoneJS doesn't refresh the page, it re-imports modules that are marked as dirty, in real-time.

The correct terminology is actually [hot swapping](https://en.wikipedia.org/wiki/Hot_swapping), not live reload. Regardless of what it's called, the result is a blazing fast development experience.

There is no configuration needed to enable this feature. Just start the dev server and begin:

```
donejs develop
```

You spend less time waiting for refreshes and builds,

...and more time doing trust falls with giant yellow M&Ms.

View the Documentation

_Live reload is a feature of [StealJS](https://stealjs.com/)._

### Generators

DoneJS generators help you kickstart new projects and components. They'll save you time, eliminating boilerplate by scaffolding a working project, component, or module.

Generator templates set up many of the best practices and features discussed in the rest of this page, without you even realizing it.

#### How it works

The DoneJS generator uses Yeoman to bootstrap your application, component, or model.

There are four generators by default (and you can easily create your own).

##### Project generator

From the command line, run:

```
donejs add app
```

You'll be prompted for a project name, source folder, and other setup information. DoneJS' project dependencies will be installed, like StealJS and CanJS. In the folder that was created, you'll see:

```
├── .yo-rc.json
├── build.js
├── development.html
├── package.json
├── production.html
├── readme.md
├── test.html
├── src/
|   ├── app.js
|   ├── index.stache
|   ├── models/
|   |   ├── fixtures
|   |   |   ├── fixtures.js
|   |   ├── test.js
|   ├── styles.less
|   ├── test.js
├── node_modules/
```

You're now a command away from running application wide tests, generating documentation, and running a build. Start your server with `donejs develop`, open your browser, and you'll see a functioning, server-side rendered hello world page.

##### Modlet component generator

To create a [component](https://canjs.com/doc/can-component.html) organized with the [modlet](#modlets) file organization pattern:

```
donejs add component <folder-path> <component-name>
```

It will create the following files:

```
restaurant/
├── list/
|   ├── list.html
|   ├── list.js
|   ├── list.less
|   ├── list.md
|   ├── list.stache
|   ├── list_test.js
|   ├── test.html
```

This folder contains everything a properly maintained component needs: a working demo page, a basic test, and documentation placeholder markdown file.

##### Simple component generator

For simple, standalone components:

```
donejs add component <file-name>.component <component-name>
```

Which will generate a working component in a single file.

##### Model generator

To create a new [model](https://canjs.com/doc/can-super-model.html):

```
donejs add supermodel <model-name>
```

This will create:

 - a working model in the application's `models` folder
 - a working fixture file for that model
 - a working test, and add the test as a dependency for the application's model test

You spend less time setting up your app,

...and more time searching for carrots.

View the Documentation
View the Guide

_Generators are provided by the [Generator DoneJS](https://github.com/donejs/generator-donejs) project with additional support via the [donejs-cli](https://github.com/donejs/cli) project_


text:
package de.hub.clickwatch.main.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EObject;

import de.hub.clickwatch.main.IClickWatchContextAdapter;
import de.hub.clickwatch.main.IProgressMonitorProvider;

public class ProgressMonitorProvider implements IClickWatchContextAdapter, IProgressMonitorProvider {

	private IProgressMonitor monitor = null;

	@Override
	public IProgressMonitor getProgressMonitor() {
		if (monitor == null) {
			return new NullProgressMonitor();
		} else {
			return monitor;
		}
	}

	@Override
	public List<Option> getCommandLineOptions() {
		return new ArrayList<Option>();
	}

	@Override
	public void initialize(CommandLine commandLine) throws ParseException {
		// empty
	}

	@Override
	public void initialize(IConfigurationElement configurationElement,
			EObject selection) {
		// empty
	}

	public void initialize(IProgressMonitor monitor) {
		this.monitor = monitor;
	}

	@Override
	public Class<?> getAdpaterClass() {
		return IProgressMonitorProvider.class;
	}

}

redpajama_set_name: RedPajamaGithub


text:
//@filename: a.ts
/*! Keep this pinned comment */
declare module C {
    function foo();
}

// Don't keep this comment.
declare module D {
    class bar { }
}

//@filename: b.ts
///<reference path="a.ts"/>
declare module E {
    class foobar extends D.bar {
        foo();
    }
}


text:
require 'spec_helper'
require 'swrve/middleware/http'
module Swrve
  module Api
    describe Resources do

      subject { Resources.new }

      let(:config) { stub_everything('config', ab_test_url: 'http://ab_test_url', api_version: 1) }

      before { Swrve.stubs(config: config) }

      describe '.new' do
        it 'Creates a resources endpoint' do
          Middleware::Http.expects(:new).with([config.ab_test_url, 'api', config.api_version].join('/'))

          subject
        end
      end

      describe '#get' do
        let(:resources_endpoint) { mock('resources_endpoint') }

        before { Middleware::Http.stubs(:new).returns(resources_endpoint) }

        it 'delegates it to the resources endpoint' do
          resources_endpoint.expects(:get)

          subject.send(:get)
        end
      end
    end
  end
end


text:
import React, {Component} from 'react'
import '../../assets/styles/home.styl'
import Hot from './hotAndWill-hot'
import Will from './hotAndWill-will'
class HotAndWill extends Component {
  constructor(props) {
    super(props)
    this.state = {
      show: 'hot',
      data: [],
      pagenum: 1,
      typestr: '正在热映'
    }
  }
  static propTypes = {
    inner: React.PropTypes.string
  }
  hotClick = (e) => {
    this.setState({
      show: 'hot',
      typestr: '正在热映'
    })
    var h2Arr = document.querySelectorAll('#hotAndWill #hotAndWill-header #hotAndWill-header-left h2')
    h2Arr.forEach(function (item, index) {
      item.className = ''
    })
    e.target.className = 'h2black'
  }
  willClick = (e) => {
    this.setState({
      show: 'will',
      typestr: '将要播出'
    })
    var h2Arr = document.querySelectorAll('#hotAndWill #hotAndWill-header #hotAndWill-header-left h2')
    h2Arr.forEach(function (item, index) {
      item.className = ''
    })
    e.target.className = 'h2black'
  }
  render() {
    var filmType = null
    if (this.state.show === 'hot') {
      filmType = <Hot />
    }
    if (this.state.show === 'will') {
      filmType = <Will />
    }
    return (

正在热映

  /

即将上映

{this.props.inner}{this.state.typestr}如下电影    更多>>

            {filmType}

    )
  }
}
export default HotAndWill


text:
import random
import unittest
import numpy as np
from pydl import Gru

class TestEncoderDecoder(unittest.TestCase):
    def testTranslateWordsIntoInitialisms(self):
        text = "Born in Vienna into one of Europe's richest families, he inherited a large fortune " \
               "from his father in 1913. He gave some considerable sums to poor artists. In a period " \
               "of severe personal depression after the first World War, he then gave away his entire " \
               "fortune to his brothers and sisters. Three of his brothers committed suicide, with " \
               "Wittgenstein contemplating it too. He left academia several times—serving as an " \
               "officer on the front line during World War I, where he was decorated a number of times " \
               "for his courage; teaching in schools in remote Austrian villages where he encountered " \
               "controversy for hitting children when they made mistakes in mathematics; and working " \
               "as a hospital porter during World War II in London where he told patients not to take " \
               "the drugs they were prescribed while largely managing to keep secret the fact that he " \
               "was one of the world's most famous philosophers."

        index_to_word = sorted(list(set(text.split(sep=" "))))
        word_to_index = {word:i for i, word in enumerate(index_to_word)}

        index_to_char = sorted(list(set([word[0].upper() for word in index_to_word])))
        char_to_index = {char:i for i, char in enumerate(index_to_char)}

        def vector_from_word(word):
            index = word_to_index[word]
            vec = np.zeros(len(index_to_word))
            vec[index] = 1
            return vec

        def word_from_vector(vector):
            index = vector.argmax()
            if vector[index] < 0.3:
                return "?"
            else:
                return index_to_word[index]

        def vector_from_char(char):
            vec = np.zeros(len(index_to_char))
            upper = char.upper()
            if upper in char_to_index:
                index = char_to_index[upper]
                vec[index] = 1
            return vec

        def char_from_vector(vector):
            index = vector.argmax()
            if vector[index] < -0.3:
                return " "
            elif vector[index] < 0.3:
                return "?"
            else:
                return index_to_char[index]

        max_seq_size = 5

        training_set = []
        for _ in range(500):
            seq_size = random.randint(1, max_seq_size)
            word_indices = [random.randrange(0, len(index_to_word)) for _ in range(seq_size)]
            words = [index_to_word[index] for index in word_indices]

            initials = [word[0].upper() for word in words]

            training_set.append(([vector_from_word(word) for word in words],
                                 [vector_from_char(char) for char in initials]))

        encoder_hidden_state_size = 50
        encoder = Gru(len(index_to_word), encoder_hidden_state_size)
        decoder = Gru(len(index_to_char) + encoder_hidden_state_size, len(index_to_char))

        encoder_h0 = np.random.uniform(-0.2, 0.2, encoder_hidden_state_size)
        decoder_h0 = np.random.uniform(-0.2, 0.2, len(index_to_char))

        end_of_sequence = np.ones(len(index_to_char)) * -1

        for epoch in range(10000):
            debug = epoch % 5000 == 0
            for word_vectors, char_vectors in random.sample(training_set, 30):
                encoder_results = {}
                encoded_state = encoder.forward_prop(word_vectors, encoder_h0, encoder_results)[-1]

                decoder_results = {}

                def decoder_input_generator(max):
                    yield np.concatenate([encoded_state, np.zeros(len(index_to_char))])

                    prev_h = decoder_results["hs"][-1]
                    resulting_char = char_from_vector(prev_h)

                    i = 0
                    while resulting_char is not " " and i <= max:
                        yield np.concatenate([encoded_state, vector_from_char(resulting_char)])
                        i += 1

                hs = decoder.forward_prop(decoder_input_generator(len(char_vectors)), decoder_h0, decoder_results)
                if len(hs) <= len(char_vectors):
                    targets = char_vectors[:len(hs)]
                else:
                    targets = char_vectors + [end_of_sequence for _ in range(len(hs) - len(char_vectors))]

                decoder_errors = [h - target for h, target in zip(hs, targets)]

                decoder.back_prop(decoder_errors, decoder_results)
                decoder.train(0.1, decoder_results)

                encoded_state_error = decoder_results["dx"][:len(encoded_state)]
                encoder_errors = ([np.zeros(encoder_hidden_state_size)] * (len(word_vectors) - 1)) + [encoded_state_error]

                encoder.back_prop(encoder_errors, encoder_results)
                encoder.train(0.1, encoder_results)

                if debug:
                    print(" ".join([word_from_vector(word_vector) for word_vector in word_vectors]))
                    print("".join([char_from_vector(h) for h in hs]))
                    print(sum([np.sum(np.square(err)) for err in decoder_errors]))

                    encoder.save("encoder")
                    decoder.save("decoder")
                    debug = False


text:
// Copyright 2006 The Bazel Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.syntax;

import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.testutil.MoreAsserts.expectThrows;
import static org.junit.Assert.fail;

import com.google.common.collect.Sets;
import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Tests of Environment.
 */
@RunWith(JUnit4.class)
public class EnvironmentTest extends EvaluationTestCase {

  @Override
  public Environment newEnvironment() {
    return newBuildEnvironment();
  }

  // Test the API directly
  @Test
  public void testLookupAndUpdate() throws Exception {
    assertThat(lookup("foo")).isNull();
    update("foo", "bar");
    assertThat(lookup("foo")).isEqualTo("bar");
  }

  @Test
  public void testHasVariable() throws Exception {
    assertThat(getEnvironment().hasVariable("VERSION")).isFalse();
    update("VERSION", 42);
    assertThat(getEnvironment().hasVariable("VERSION")).isTrue();
  }

  @Test
  public void testDoubleUpdateSucceeds() throws Exception {
    update("VERSION", 42);
    assertThat(lookup("VERSION")).isEqualTo(42);
    update("VERSION", 43);
    assertThat(lookup("VERSION")).isEqualTo(43);
  }

  // Test assign through interpreter, lookup through API:
  @Test
  public void testAssign() throws Exception {
    assertThat(lookup("foo")).isNull();
    eval("foo = 'bar'");
    assertThat(lookup("foo")).isEqualTo("bar");
  }

  // Test update through API, reference through interpreter:
  @Test
  public void testReference() throws Exception {
    setFailFast(false);
    try {
      eval("foo");
      fail();
    } catch (EvalException e) {
      assertThat(e).hasMessage("name 'foo' is not defined");
    }
    update("foo", "bar");
    assertThat(eval("foo")).isEqualTo("bar");
  }

  // Test assign and reference through interpreter:
  @Test
  public void testAssignAndReference() throws Exception {
    setFailFast(false);
    try {
      eval("foo");
      fail();
    } catch (EvalException e) {
      assertThat(e).hasMessage("name 'foo' is not defined");
    }
    eval("foo = 'bar'");
    assertThat(eval("foo")).isEqualTo("bar");
  }

  @Test
  public void testBuilderRequiresSemantics() throws Exception {
    try (Mutability mut = Mutability.create("test")) {
      IllegalArgumentException expected =
          expectThrows(
              IllegalArgumentException.class,
              () -> Environment.builder(mut).build());
      assertThat(expected).hasMessageThat()
          .contains("must call either setSemantics or useDefaultSemantics");
    }
  }

  @Test
  public void testGetVariableNames() throws Exception {
    Environment outerEnv;
    Environment innerEnv;
    try (Mutability mut = Mutability.create("outer")) {
      outerEnv =
          Environment.builder(mut)
              .useDefaultSemantics()
              .setGlobals(Environment.DEFAULT_GLOBALS)
              .build()
              .update("foo", "bar")
              .update("wiz", 3);
    }
    try (Mutability mut = Mutability.create("inner")) {
      innerEnv = Environment.builder(mut)
          .useDefaultSemantics()
          .setGlobals(outerEnv.getGlobals())
          .build()
          .update("foo", "bat")
          .update("quux", 42);
    }

    assertThat(outerEnv.getVariableNames())
        .isEqualTo(
            Sets.newHashSet(
                "foo",
                "wiz",
                "False",
                "None",
                "True",
                "all",
                "any",
                "bool",
                "dict",
                "dir",
                "enumerate",
                "fail",
                "getattr",
                "hasattr",
                "hash",
                "int",
                "len",
                "list",
                "max",
                "min",
                "print",
                "range",
                "repr",
                "reversed",
                "sorted",
                "str",
                "tuple",
                "zip"));
    assertThat(innerEnv.getVariableNames())
        .isEqualTo(
            Sets.newHashSet(
                "foo",
                "wiz",
                "quux",
                "False",
                "None",
                "True",
                "all",
                "any",
                "bool",
                "dict",
                "dir",
                "enumerate",
                "fail",
                "getattr",
                "hasattr",
                "hash",
                "int",
                "len",
                "list",
                "max",
                "min",
                "print",
                "range",
                "repr",
                "reversed",
                "sorted",
                "str",
                "tuple",
                "zip"));
  }

  @Test
  public void testToString() throws Exception {
    update("subject", new StringLiteral("Hello, 'world'."));
    update("from", new StringLiteral("Java"));
    assertThat(getEnvironment().toString()).isEqualTo("<Environment[test]>");
  }

  @Test
  public void testBindToNullThrowsException() throws Exception {
    try {
      update("some_name", null);
      fail();
    } catch (NullPointerException e) {
      assertThat(e).hasMessage("update(value == null)");
    }
  }

  @Test
  public void testFrozen() throws Exception {
    Environment env;
    try (Mutability mutability = Mutability.create("testFrozen")) {
      env =
          Environment.builder(mutability)
              .useDefaultSemantics()
              .setGlobals(Environment.DEFAULT_GLOBALS)
              .setEventHandler(Environment.FAIL_FAST_HANDLER)
              .build();
      env.update("x", 1);
      assertThat(env.lookup("x")).isEqualTo(1);
      env.update("y", 2);
      assertThat(env.lookup("y")).isEqualTo(2);
      assertThat(env.lookup("x")).isEqualTo(1);
      env.update("x", 3);
      assertThat(env.lookup("x")).isEqualTo(3);
    }
    try {
      // This update to an existing variable should fail because the environment was frozen.
      env.update("x", 4);
      throw new Exception("failed to fail"); // not an AssertionError like fail()
    } catch (AssertionError e) {
      assertThat(e).hasMessage("Can't update x to 4 in frozen environment");
    }
    try {
      // This update to a new variable should also fail because the environment was frozen.
      env.update("newvar", 5);
      throw new Exception("failed to fail"); // not an AssertionError like fail()
    } catch (AssertionError e) {
      assertThat(e).hasMessage("Can't update newvar to 5 in frozen environment");
    }
  }

  @Test
  public void testReadOnly() throws Exception {
    Environment env = newSkylarkEnvironment()
        .setup("special_var", 42)
        .update("global_var", 666);

    // We don't even get a runtime exception trying to modify these,
    // because we get compile-time exceptions even before we reach runtime!
    try {
      BuildFileAST.eval(env, "special_var = 41");
      throw new AssertionError("failed to fail");
    } catch (EvalException e) {
      assertThat(e).hasMessageThat().contains("Variable special_var is read only");
    }

    try {
      BuildFileAST.eval(env, "def foo(x): x += global_var; global_var = 36; return x", "foo(1)");
      throw new AssertionError("failed to fail");
    } catch (EvalExceptionWithStackTrace e) {
      assertThat(e)
          .hasMessageThat()
          .contains(
              "Variable 'global_var' is referenced before assignment. "
                  + "The variable is defined in the global scope.");
    }
  }
}


text:
'use strict';

import {Registry} from 'vs/platform/platform';
import {ICommandHandler, ICommandsMap, IKeybindingItem, IKeybindings, IKeybindingContextRule} from 'vs/platform/keybinding/common/keybindingService';
import {KeybindingsUtils} from 'vs/platform/keybinding/common/keybindingsUtils';
import {KeyMod, KeyCode, BinaryKeybindings} from 'vs/base/common/keyCodes';
import Platform = require('vs/base/common/platform');

export interface ICommandRule extends IKeybindings {
	id: string;
	weight: number;
	context: IKeybindingContextRule[];
}

export interface ICommandDescriptor extends ICommandRule {
	handler: ICommandHandler;
}

export interface IKeybindingsRegistry {
	registerCommandRule(rule:ICommandRule);
	registerCommandDesc(desc: ICommandDescriptor): void;
	getCommands(): ICommandsMap;
	getDefaultKeybindings(): IKeybindingItem[];

	KEYBINDING_CONTEXT_OPERATOR_EQUAL: string;
	KEYBINDING_CONTEXT_OPERATOR_NOT_EQUAL: string;

	WEIGHT: {
		editorCore(importance?: number): number;
		editorContrib(importance?: number): number;
		workbenchContrib(importance?: number): number;
		builtinExtension(importance?:number): number;
		externalExtension(importance?:number): number;
	};
}

class KeybindingsRegistryImpl implements IKeybindingsRegistry {

	private _keybindings: IKeybindingItem[];
	private _commands: ICommandsMap;

	public KEYBINDING_CONTEXT_OPERATOR_EQUAL = 'equal';
	public KEYBINDING_CONTEXT_OPERATOR_NOT_EQUAL = 'not_equal';

	public WEIGHT = {
		editorCore: (importance: number = 0): number => {
			return 0 + importance;
		},
		editorContrib: (importance: number = 0): number => {
			return 100 + importance;
		},
		workbenchContrib: (importance: number = 0): number => {
			return 200 + importance;
		},
		builtinExtension: (importance:number = 0): number => {
			return 300 + importance;
		},
		externalExtension: (importance:number = 0): number => {
			return 400 + importance;
		}
	};

	constructor() {
		this._keybindings = [];
		this._commands = Object.create(null);
	}

	public registerCommandRule(rule:ICommandRule): void {
		var actualKb = KeybindingsUtils.bindToCurrentPlatform(rule);

		if (actualKb && actualKb.primary) {
			this.registerDefaultKeybinding(actualKb.primary, rule.id, rule.weight, 0, rule.context);
		}

		if (actualKb && Array.isArray(actualKb.secondary)) {
			actualKb.secondary.forEach((k, i) => this.registerDefaultKeybinding(k, rule.id, rule.weight, -i - 1, rule.context));
		}
	}

	public registerCommandDesc(desc: ICommandDescriptor): void {
		this.registerCommandRule(desc);

		// if (_commands[desc.id]) {
		// 	console.warn('Duplicate handler for command: ' + desc.id);
		// }
		// this._commands[desc.id] = desc.handler;
		this._commands[desc.id] = desc.handler;
	}

	public getCommands(): ICommandsMap {
		return this._commands;
	}

	private registerDefaultKeybinding(keybinding: number, commandId:string, weight1: number, weight2:number, context:IKeybindingContextRule[]): void {
		if (Platform.isWindows) {
			if (BinaryKeybindings.hasCtrlCmd(keybinding) && !BinaryKeybindings.hasShift(keybinding) && BinaryKeybindings.hasAlt(keybinding) && !BinaryKeybindings.hasWinCtrl(keybinding)) {
				if (/^[A-Z0-9\[\]\|\;\'\,\.\/\`]$/.test(KeyCode.toString(BinaryKeybindings.extractKeyCode(keybinding)))) {
					console.warn('Ctrl+Alt+ keybindings should not be used by default under Windows. Offender: ', keybinding, ' for ', commandId);
				}
			}
		}
		if (Platform.isLinux) {
			if (!BinaryKeybindings.hasCtrlCmd(keybinding) && !BinaryKeybindings.hasShift(keybinding) && BinaryKeybindings.hasAlt(keybinding) && !BinaryKeybindings.hasWinCtrl(keybinding)) {
				console.warn('Alt+ keybindings should not be used by default under Linux. Offender: ', keybinding, ' for ', commandId);
			}
		}
		this._keybindings.push({
			keybinding: keybinding,
			command: commandId,
			context: context,
			weight1: weight1,
			weight2: weight2
		});
	}

	public getDefaultKeybindings(): IKeybindingItem[] {
		return this._keybindings;
	}
}
export var KeybindingsRegistry:IKeybindingsRegistry = new KeybindingsRegistryImpl();

// Define extension point ids
export var Extensions = {
	EditorModes: 'platform.keybindingsRegistry'
};
Registry.add(Extensions.EditorModes, KeybindingsRegistry);


text:
import React from 'react';
import { Field } from 'redux-form/immutable';
import { isEmpty } from 'lodash';
import { ModalBody, ModalFooter } from 'elemental';

import formFactory from '../formFactory';

import InputField from '../../../../components/InputField';

export class FormContent extends React.Component {
  render() {
    const { handleSubmit, store, closeModal, item, pristine, errors } = this.props;

    return (
      <form onSubmit={handleSubmit}>
        <ModalBody>

Please enter your name and email to reserve {item.name}

          <fieldset className="container">

              <Field name="name" placeholder="Jane Smith" component={InputField} type="text" store={store}/>

              <Field name="email" placeholder="Jane@gmail.com" component={InputField} type="email" store={store}/>

          </fieldset>
        </ModalBody>
        <ModalFooter>
          <button className="button" onClick={handleSubmit} disabled={pristine || !isEmpty(errors)}>Reserve</button>
          <button className="button button-clear" onClick={closeModal}>Cancel</button>
        </ModalFooter>
      </form>
    );
  }
}

export default formFactory(FormContent);