[
  {
    "path": ".gitignore",
    "content": "_site\n"
  },
  {
    "path": "LICENSE",
    "content": "Licensed under the Apache License, Version 2.0 (the \"License\"); you\nmay not use this file except in compliance with the License. You may\nobtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\nimplied. See the License for the specific language governing\npermissions and limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# CouchDB Best Practices\nCollect best practices around the CouchDB universe.\n\n\n* [Basics](#basics)\n  * [Reserved Properties, IDs and Revisions](#reserved-properties,-ids-and-revisions)\n* [Bootstrap](#bootstrap)\n  * [CouchDB Compile](#couchdb-compile)\n  * [Configure CouchDB](#configure-couchdb)\n  * [Create Databases](#create-databases)\n  * [Secure a Database](#secure-a-database)\n  * [Deploy Documents](#deploy-documents)\n  * [Complete Bootstrap](#complete-bootstrap)\n* [User Management](#user-management)\n  * [Creating Admin User](#creating-admin-user)\n  * [Creating User](#creating-user)\n  * [Change Password](#change-password)\n* [Document Modelling](#document-modeling)\n  * [Embrace the Document ID](#embrace-the-document-id)\n  * [Document Modeling To Avoid Conflicts](#document-modeling-to-avoid-conflicts)\n  * [Document Validations](#document-validations)\n  * [Data Migrations](#data-migrations)\n  * [Per Document Access Control](#per-document-access-control)\n  * [Useful Meta Keys](#useful-meta-keys)\n  * [A Note on Dates](#a-note-on-dates)\n  * [One To N Relations](#one-to-n-relations)\n  * [N To N Relations](#n-to-n-relations)\n* [Views](#views)\n  * [Do Not Emit Entire Docs](#do-not-emit-entire-docs)\n  * [Linked Documents](#linked-documents)\n  * [Built-In Reduce Functions](#built-in-reduce-functions)\n  * [Debugging Views](#debugging-views)\n  * [Testing Views](#testing-views)\n  * [Deploying Views](#deploying-views)\n  * [Modularize View Code](#modularize-view-code)\n  * [View Collation](#view-collation)\n  * [Group Level](#group-level)\n  * [Naming Conventions For Views](#naming-conventions-for-views)\n* [Replication](#replication)\n  * [Filtered Replication](#filtered-replication)\n  * [Using Replication](#using-replication)\n* [Conflicts](#conflicts)\n  * [Conflict Handling](#conflict-handling)\n* [Deployment](#deployment)\n  * [CouchDB Behind A Proxy](#couchdb-behind-a-proxy)\n* [Misc](#misc)\n  * [Debugging PouchDB](#debugging-pouchdb)\n  * [PouchDB and AngularJS](#pouchdb-and-angularjs)\n  * [Full Text Search](#full-text-search)\n  * [Two Ways of Deleting Documents](#two-ways-of-deleting-documents)\n\n\n## Basics\n> Apache CouchDB™ is a database that uses JSON for documents, JavaScript for\nMapReduce indexes, and regular HTTP for its API.\n\nWebsite: [couchdb.apache.org](http://couchdb.apache.org/)  \nDocs: [docs.couchdb.org](http://docs.couchdb.org/en/1.6.1/)  \nBlog: [blog.couchdb.org](http://blog.couchdb.org/)  \nOld Wiki: [wiki.apache.org](https://wiki.apache.org/couchdb/)  \nNew Wiki: [cwiki.apache.org](https://cwiki.apache.org/confluence/display/COUCHDB/Apache+CouchDB+Wiki)  \nUser List: [user@couchdb.apache.org](http://mail-archives.apache.org/mod_mbox/couchdb-user/)  \nGithub: [apache/couchdb](https://github.com/apache/couchdb)  \nIRC: [irc.freenode.net/couchdb](irc://irc.freenode.net/couchdb)  \n\n### Reserved Properties, IDs and Revisions\nAny top-level fields within a JSON document containing a name that starts with a\n`_` prefix are reserved for use by CouchDB itself.\n\nIf you don't specify an `_id` CouchDB will create one for you. You can configure\nin `uuids/algorithm` which algorithm will be used: `random`, `sequential` or\n`utc_random`.\n\nDocument revisions are used for optimistic concurrency control. If you try to\nupdate a document using an old revision the update will be in conflict. These\nconflicts should be resolved by your client, usually by requesting the newest\nversion of the document, modifying and trying the update again. \n\n## Bootstrap\nBootstrap means in our case the preparation of the database in order to make it\nready to run your project. In this process we configure CouchDB from a file\nwhich lives inside your project root, create the needed databases and deploy map\nfunctions and more, conveniently also from plain JavaScript files (or Erlang or\nHaskell or Ruby or whatever language you prefer for your views).\n\nIn order to make this process as seemless as possible we have created\n[CouchDB Bootstrap](https://github.com/jo/couchdb-bootstrap). You can\ninstall it with npm:\n\n```sh\n$ npm install --global couchdb-bootstrap\n```\n\nCouchDB Bootstrap combines a set of small tools, which can be used\nindependently. Each of those tools come has a similar API and is shipped with a\nCLI:\n\n* [couchdb-compile](https://github.com/jo/couchdb-compile) - Handle sources: fs mapping / JSON / CommonJS\n* [couchdb-configure](https://github.com/jo/couchdb-configure) - Configure CouchDB\n* [couchdb-ensure](https://github.com/jo/couchdb-ensure) - Create database unless exists\n* [couchdb-secure](https://github.com/jo/couchdb-secure) - Secure databases: write security object\n* [couchdb-push](https://github.com/jo/couchdb-push) - Push documents: users, replications, design docs and normal documents\n\nIts best you install altogether right now:\n\n```sh\n$ npm install --global couchdb-bootstrap couchdb-compile couchdb-configure couchdb-ensure couchdb-push couchdb-secure\n```\n\nFirst we setup a couchdb folder inside your project:\n\n```sh\ncouchdb\n├── ...\n└── ...\n```\n\nThis folder is organized just like CouchDBs URLS: we have a `/_config.json` file (or\nfolder, more about that below) and `_users`, `_replicator` and custom databases.\n\n### CouchDB Compile\nWhen we talk about compilation we mean the transformation of a folder into a\nCouchDB JSON document. Map functions for example need to be stored as strings in\ndesign documents. Design documents are just like normal documents with an id\nthat is prefixed with `_design/`:\n\n```json\n{\n  \"_id\": \"_design/myapp\",\n  \"views\": {\n    \"by-date\": {\n      \"map\": \"function(doc) { if ('date' in doc) emit(doc.date, null) }\"\n    }\n  }\n}\n```\n\nYou do not want to deal with the JSON encoding and want your view functions code\nchecked into Git as *files*. Thats why the CouchDB Filesystem Mapping was\ninvented. The idea is simple: every key in the JSON document corresponds to a\ndirectory if the value is an object, otherwise to a file, which contents will\nmake the value:\n\n```sh\nmyapp\n├── _id             # contains `_design/myapp`\n└── views\n    └── by-date\n        └─── map.js # contains `function(doc) { if ('date' in doc) emit(doc.date, null) }`\n```\n\nWe use [Couchdb Compile](https://github.com/jo/couchdb-compile) and run\n`couchdb-compile` on this directory to get a JSON from those files:\n\n```sh\n[myapp]$ couchdb-compile \n{\n  \"_id\": \"_design/myapp\",\n  \"views\": {\n    \"by-date\": {\n      \"map\": \"function(doc) {\\n  if ('date' in doc) emit(doc.date, null)\\n}\"\n    }\n  }\n}\n```\n\n#### JSON Files\n\nSometimes you don't want this excessive deep nested directory tree. You can\nabbreviate by using a JSON file. CouchDB Compile will use the filename as key\n(without the `.json` extension) and take the contents of that as value. Lets\nplace an `package.json` file in the `myapp` directory with the following\ncontent:\n\n```json\n{\n  \"name\": \"My Shiny Application\",\n  \"description\": \"My Shiny Application helps everybody to discover your brilliancy.\"\n}\n```\n\nWhen we compile the `myapp` directory again the `package.json` file gets included:\n\n```sh\n[myapp]$ couchdb-compile \n{\n  \"_id\": \"_design/myapp\",\n  \"views\": {\n    \"by-date\": {\n      \"map\": \"function(doc) {\\n  if ('date' in doc) emit(doc.date, null)\\n}\"\n    }\n  },\n  \"package\": {\n    \"name\": \"My Shiny Application\",\n    \"description\": \"My Shiny Application helps everybody to discover your brilliancy.\"\n  }\n}\n```\n\n\n#### ID Derivation from Filename\n\nThats great. You might argue about the duplicated information found both inside\nthe id and in the filename. Thats why CouchDB Compile derives the `_id`\nproperty from the filename in case the id is not included in the final JSON. So\nlets change our directory to look like this:\n\n```sh\n_design\n└── myapp\n    ├── package.json\n    └── views\n        └── by-date\n            └─── map.js\n```\n\nThe result is the same, but this time we have omitted the `_id` file.  Note\nthat CouchDB Compile not only considers the filename but also checks the parent\ndirectory. If it is `_design` or `_local` and if so, prepends it, too.\n\n#### CommonJS Modules (AKA Node Modules)\nI hear everybody scream:\n\n_\"How can I test my view? The view code even is no valid JavaScript at all!\"_\n\nCommonJS modules to the rescue! Besides filesystem mapping and JSON CouchDB\nCompile also supports CommonJS modules. Consider the following files:\n\n```sh\n_design/\n└── myapp\n    ├── index.js\n    └── package.json\n    └── views\n        └── by-date.js\n\n```\n\n##### \\_design/myapp/index.js\nJust like a normal node module we use an index.js file as an entry point to our\ndocument (you can also use an myapp.js file instead):\n\n```js\nexports.package = require('./package.json')\nexports.views = {\n  'by-date': require('./views/by-date')\n}\n```\n\n##### \\_design/myapp/views/by-date.js\nNow everything is common js:\n\n```js\nexports.map = function(doc) {\n  if ('date' in doc) emit(doc.date, null)\n}\n```\n\nAgain, we get the same result as before when we run `couchdb-compile --index`.\nRemember that we need to enable this feature with the `--index` flag.\n\nThis is the most flexible way to structure your files and also gives us\ntestability, because the views are now plain CommonJS modules.\n\n\n### Configure CouchDB\nCouchDB not only exposes its configuration over HTTP, configuration settings can also be altered via HTTP.\n\nFor example, you might want to enable CORS. For this you must change a bunch of\nsettings. Write the following JSON to a `_config.json` file (or grab it from\n[couchdb-cors-config](https://github.com/jo/couchdb-cors-config)):\n\n```json\n{\n  \"httpd\": {\n    \"enable_cors\": true\n  },\n  \"cors\": {\n    \"origins\": \"*\",\n    \"credentials\": true,\n    \"methods\": [\n      \"GET\",\n      \"PUT\",\n      \"POST\",\n      \"HEAD\",\n      \"DELETE\"\n    ],\n    \"headers\": [\n      \"accept\",\n      \"authorization\",\n      \"content-type\",\n      \"origin\",\n      \"referer\",\n      \"x-csrf-token\"\n    ]\n  }\n}\n```\n\nWe can now write that configuration with [CouchDB\nConfigure](https://github.com/jo/couchdb-configure). The\nconfiguration will be used immediately - no restart required:\n\n```sh\n$ couchdb-configure http://localhost:5984 _config.json \n{\n  \"httpd/enable_cors\": {\n    \"ok\": true,\n    \"value\": \"true\"\n  },\n  \"cors/origins\": {\n    \"ok\": true,\n    \"value\": \"*\"\n  },\n  \"cors/credentials\": {\n    \"ok\": true,\n    \"value\": \"true\"\n  },\n  \"cors/methods\": {\n    \"ok\": true,\n    \"value\": \"GET,PUT,POST,HEAD,DELETE\"\n  },\n  \"cors/headers\": {\n    \"ok\": true,\n    \"value\": \"accept,authorization,content-type,origin,referer,x-csrf-token\"\n  }\n}\n```\n\nCouchDB Configure uses CouchDB Compile under the hood so you have all the\noptions to define your configuration as files, JSON or CommonJS module.\n\n### Create Databases\nYou can create a database with [CouchDB\nEnsure](https://github.com/jo/couchdb-ensure):\n\n```sh\n$ couchdb-ensure http://localhost:5984/mydb\n{\n  \"ok\": true\n}\n```\n\nIf it does already exist nothing happens.\n\n### Secure a Database\nCouchDB is *absolutely open by default*. That means everybody can write\ndocuments (except design documents) and everybody can read every document.\n\nThis can be changed on a per database basis by altering the security object:\n\n> The security object consists of two compulsory elements, admins and members, which are used to specify the list of users and/or roles that have admin and members rights to the database respectively:\n\n>>    `members`: they can read all types of documents from the DB, and they can write (and edit) documents to the DB except for design documents.   \n>>    `admins`: they have all the privileges of members plus the privileges: write (and edit) design documents, add/remove database admins and members, set the database revisions limit and execute temporary views against the database. They can not create a database nor delete a database.\n\nFrom the [CouchDB\ndocumentation](http://docs.couchdb.org/en/latest/api/database/security.html).\n\nA simple security object looks like this:\n\n```json\n{\n  \"admins\": {\n    \"names\": [],\n    \"roles\": []\n  },\n  \"members\": {\n    \"names\": [],\n    \"roles\": [\n      \"myapp-user\"\n    ]\n  }\n}\n```\n\nHere, access is only permitted to database admins and users with the role `myapp-user`.\n\nUse [CouchDB Secure](https://github.com/jo/couchdb-secure) to alter\nthe security object:\n\n```sh\n$ couchdb-secure _security.json\n{\n  \"ok\": true\n}\n```\n\nCouchDB Secure uses CouchDB Compile under the hood so you have all the options\nto define your security object as files, JSON or CommonJS module.\n\n\n### Deploy Documents\n[CouchDB Push](https://github.com/jo/couchdb-push) can be used to deploy\ndocuments, be it design documents, users, replications or ordinary documents to\na CouchDB database. Under the hood CouchDB Compile is used, so the everything\nyou have learned about compilation above is also valid here.\n\n```sh\n[myapp]$ couchdb-push http://localhost:5984/mydb\n{\n  \"ok\": true,\n  \"id\": \"_design/myapp\",\n  \"rev\": \"1-e2dfeb85f19c981e311144a6105d7de8\"\n}\n```\n\n### Complete Bootstrap\nNow you have all in place to understand [CouchDB\nBootstrap](https://github.com/jo/couchdb-bootstrap).\nWhile CouchDB Push acts on document level, CouchDB Bootstrap acts on the server\nlevel. Here you can organize different databases, users, replications and\nconfiguration:\n\n```sh\ncouchdb\n├── _config.json\n├── _replicator\n│   ├── setup-alice.json\n│   └── setup-bob.json\n├── _users\n│   ├── alice.json\n│   └── bob.json\n├── myapp-db\n│   ├── _design\n│   │   └── myapp.js\n│   ├── _security.json\n│   └── adoc.json\n├── myapp-alice-db\n│   └── _security.json\n└── myapp-bob-db\n    └── _security.json\n```\n\nThe whole project can now be bootstrapped with\n\n```sh\n[couchdb]$ couchdb-bootstrap http://localhost:5984\n```\n\n\n# Admin User\nFirst thing to do is setup the user account\n\n* Go to [http://localhost:5984/_utils/](http://localhost:5984/_utils) in your web browser\n* Click on `Setup more admins` in the bottom right hand corner of the sidebar\n* Enter a username + password (this will be the root admin of your CouchDB)\n* Click on `Logout` which is also in bottom right had corner\n\nGreat, now you've configured your Admin User. However, you don't want to\nactually use this account to do things, so proceed!\n\n\n### Creating User\nTo create a non admin user, follow these steps:\n\n* While still on `http://localhost:5984/_utils/` in your browser (and logged out)\n* Click on `Signup` in the bottom right of the sidebar\n* Enter username + password\n\n\n### Change Password\nSince CouchDB 1.2 updating the user password has become much easier:\n\n1. Request the user doc: `GET /_users/org.couchdb.user:a-username`\n2. Set a `password` property with the password\n3. Save the doc\n\nThe [User authentication plugin for PouchDB and\nCouchDB](https://github.com/nolanlawson/pouchdb-authentication) provides a\n[`changePassword`](https://github.com/nolanlawson/pouchdb-authentication#user-content-dbchangepasswordusername-password--opts-callback)\nfunction for your convenience.\n\n\n## Document Modeling\n\n### Embrace the Document ID\nIn CouchDB ids can be arbitrary strings. Make use of this!\n\nThe id cannot be changed afterwards, instead you can move a document via COPY\nand DELETE.\n\nBefore deciding on using a random value as doc `_id`, read the section [When not\nto use map\nreduce](http://pouchdb.com/2014/05/01/secondary-indexes-have-landed-in-pouchdb.html)\n\n*Use domain specific document ids* where possible. With CouchDB it is best\npractice to use meaningful ids.\n\nYou can use the tiny [to-id](https://github.com/gr2m/to-id) module to normalize\nnames, titles and other properties for use as id.\n\nWhen splitting documents into different subdocuments I often include the parent\ndocument id in the id. Use [docuri](https://github.com/jo/docuri/) to centralize\ndocument id knowledge.\n\n#### A note about `/` in document ids\n*Slashes are totally fine in document ids* and widely used. However, a specific\ndeployment setup (nginx proxy with subdirectory rewrite) might require\nyou to not use slashes in document ids. Thats the reason we use colons here.\n\nNote that you have to encode the document id, when used in an url, but you should\ndo that anyway.\n\n#### Use document ids to enforce uniqueness\nThe only way to enforce something is unique is to include it in the document id.\n\nFor example, in the *\\_users* database the username is part of the id:\n\n```json\n{\n  \"_id\": \"org.couchdb.user:jo@die-tf.de\",\n  \"_rev\": \"1-64db269b26ed399733beb259d1a31304\",\n  \"name\": \"jo@die-tf.de\",\n  \"type\": \"user\"\n}\n```\n\n\n### Document Modeling to Avoid Conflicts\nAt the moment of writing, most of our data documents are modeled as ‘one big\ndocument’. This is not according to CouchDB best practice. *Split data into many\nsmall documents* depending on how often and when data changes.  That way, you can\navoid conflicts and conflict resolution by just appending new documents to the\ndatabase. Its often a good idea to have many small documents versus less big\ndocuments. As a guideline on how to model documents *think about when data\nchanges*. Data that changes together, belongs in a document. Modelling documents\nthis way a) avoids conflicts and b) keeps the number of revisions low, which\nimproves replication performance and uses less storage.\n\n\n### Document Validations\nTo enforce a certain document schema use [Validate document update\nfunctions](http://docs.couchdb.org/en/1.6.1/couchapp/ddocs.html#vdufun).\n\nOn every document write (via PUT, POST, DELETE or `_bulk_docs`) the validation function,\nif present, gets called. Validation functions live in design documents in the\nspecial `validate_doc_update` property. You can have many validation\nfunctions, each in different design documents.\nIf any of the validation function throws an error, the update gets rejected and\nthe error message gets returned to the client.\nNote that validation is also triggered during replication causing documents to\nget rejected if they do not meet criteria defined in the target database\nvalidations.\n\nAn example validation, which denies document deletion for non admins, look like\nthis:\n\n```js\nfunction(newDoc, oldDoc, userCtx, secObj) {\n  if (newDoc._deleted && userCtx.roles.indexOf('_admin') === -1) {\n    throw({\n      forbidden: 'Only admins may delete user docs.'\n    })\n  }\n}\n```\n\nThe document to validate and the old document gets passed to the function, along\nwith a [User Context\nObject](http://docs.couchdb.org/en/1.6.1/json-structure.html#userctx-object) and\n[Security\nObject](http://docs.couchdb.org/en/1.6.1/json-structure.html#security-object)\n\n\n### Data Migrations\n@mdumke and me (@jo) have written a comprehensive guide on [Distributed Migration Strategies](https://sync-tank.com/distributed-migration-strategies/). Worth to check out.\n\nUse [pouchdb-migrate](https://github.com/jo/pouchdb-migrate), a\nPouchDB plugin to help with migrations.\n\nYou can either run migration on startup (the plugin remembers if a replication has\nalready been run, so the extra cost on startup is getting a single local document)\nor you can setup a daemon on the server.\n\nIts also possible to run a migration manually from a dev computer.\n\nPlease take care of your migration function. It *must* recognize whether a doc\nalready has been migrated, otherwise the migration is caught in a loop!\n\n\n### Per Document Access Control\nThere is no way to [control document-level\naccess](https://github.com/apache/couchdb/issues/1524) yet, but it is in the\nworks.\n\nIn the meantime, a common solution is to have a database per user.\n\nTo create the dbs, you need to install a daemon. There are different projects:\n\n* [couchperuser](https://github.com/etrepum/couchperuser) (Erlang, donated to Apache CouchDB)\n* [couchdb-dbperuser-provisioning](https://github.com/pegli/couchdb-dbperuser-provisioning) (Node)\n\nAn other way to achive per document access control, even on a per field basis, is\nto use encryption. [crypto-pouch](https://github.com/calvinmetcalf/crypto-pouch)\nand [pouch-box](https://github.com/jo/pouch-box) might help.\n\n\n### Useful Meta Keys\nIn documents some information is generally useful. Rails, for example, inserts\ntimestamps per default.:\n\n* `created_at`: Date of creation\n* `updated_at`: Date of last update\n* `created_by`: Username of creator\n* `updated_by`: Username of last updater\n* `type`: Document type\n* `version`: Document schema version\n\nYou can add validations, which takes care that those fields are set. Nonetheless\nyou cannot guarantee that dates are correct - just that they are in the right\nformat.\n\n\n### A Note on Dates\nWhen saving dates, just store them as [ISO\n8601](http://en.wikipedia.org/wiki/ISO_8601) strings, created by\n`.toISOString()` as well as by `JSON.stringify()`. That way the dates can be\neasily consumed by `new Date` or, who prefers, parsed by `Date.parse()`:\n\n```js\nvar date = new Date()\n// Mon May 18 2015 16:50:52 GMT+0200 (CEST)\nvar datestring = date.toJSON()\n// '2015-05-18T14:50:52.018Z'\nnew Date(datestring)\n// Mon May 18 2015 16:50:52 GMT+0200 (CEST)\n```\n\n\n### One To N Relations\nOf course you can just use an array inside the document to store related data.\nThis has a downside when the related data has to be updated, because conflicts\ncan be created and this also introduces growing revisions which affects replication\nperformance.\n\nIts best to store related data in an extra document. You can use the id to link\nthe documents together. That way you don't even need a view to fetch them together.\n\n```json\n{\n  \"_id\": \"artist:tom-waits\",\n  \"name\": \"Tom Waits\"\n}\n```\n\n```json\n[\n  {\n    \"_id\": \"artist:tom-waits:album:closing-time\",\n    \"title\": \"Closing Time\"\n  }\n  {\n    \"_id\": \"artist:tom-waits:album:rain-dogs\",\n    \"title\": \"Rain Dogs\"\n  }\n  {\n    \"_id\": \"artist:tom-waits:album:real-gone\",\n    \"title\": \"Real Gone\"\n  }\n]\n```\n\nNow you can use the built-in `_all_docs` view to query the artist and all of its\nalbums together, using start- and endkey:\n\n```json\n{\n  \"include_docs\": true,\n  \"startkey\": \"artist:tom-waits:\",\n  \"endkey\": \"artist:tom-waits:\\ufff0\"\n}\n```\n\n### N To N Relations\nSimilar to 1:N relations but use extra documents which describes each relation:\n\n```json\n[\n  {\n    \"_id\": \"person:avery-mcdonalid\",\n    \"name\": \"Avery Mcdonalid\"\n  },\n  {\n    \"_id\": \"person:troy-howell\",\n    \"name\": \"Troy Howell\"\n  },\n  {\n    \"_id\": \"person:tonya-payne\",\n    \"name\": \"Tonya Payne\"\n  }\n]\n```\n\n```json\n[\n  {\n    \"_id\": \"friendship:person:avery-mcdonalid:with:person:troy-howell\",\n    \"since\": \"2015-05-13T08:57:53.786Z\"\n  },\n  {\n    \"_id\": \"friendship:person:avery-mcdonalid:with:person:tonya-payne\",\n    \"since\": \"2015-03-02T07:21:01.123Z\"\n  }\n]\n```\n\nNote how we used a deterministic order of friends in the id, we just sorted them\nalphabetically. Its important to be able to derivate the friendship document id\nfrom the constituting ids to make it easy to delete a relation.\n\n\nNow write a map function like this:\n\n```js\nfunction(doc) {\n  if (!doc._id.match(/^friendship:/)) return\n  \n  var ids = doc._id.match(/person:[^:]*/g)\n  var one = ids[0]\n  var two = ids[1]\n\n  emit([one, two], { _id: two })\n  emit([two, one], { _id: one })\n}\n```\n\nYou now can query the view for one person:\n\n```json\n{\n  \"include_docs\": true,\n  \"startkey\": [\"person:avery-mcdonalid\"],\n  \"endkey\": [\"person:avery-mcdonalid\", {}]\n}\n```\n\nand get all friends of that person:\n\n```json\n{\n  \"total_rows\" : 4,\n  \"rows\" : [\n    {\n      \"doc\" : {\n        \"name\" : \"Tonya Payne\",\n        \"_rev\" : \"1-7aafe790e8f4f00220c699e966246421\",\n        \"_id\" : \"person:tonya-payne\"\n      },\n      \"value\" : {\n        \"_id\" : \"person:tonya-payne\"\n      },\n      \"id\" : \"friendship:person:avery-mcdonalid:with:person:tonya-payne\",\n      \"key\" : [\n        \"person:avery-mcdonalid\",\n        \"person:tonya-payne\"\n      ]\n    },\n    {\n      \"value\" : {\n        \"_id\" : \"person:troy-howell\"\n      },\n      \"doc\" : {\n        \"_rev\" : \"1-7e0328a9eb72a5544663c30052c67161\",\n        \"_id\" : \"person:troy-howell\",\n        \"name\" : \"Troy Howell\"\n      },\n      \"key\" : [\n        \"person:avery-mcdonalid\",\n        \"person:troy-howell\"\n      ],\n      \"id\" : \"friendship:person:avery-mcdonalid:with:person:troy-howell\"\n    }\n  ],\n  \"offset\" : 0\n}\n```\n\n## Views\n\n### Do Not Emit Entire Docs\nYou can query a view with `include_docs=true`. Then in the view result every row has\nthe whole doc included:\n\n```json\n{\n  \"rows\": [\n    {\n      \"id\": \"mydoc\",\n      \"key\": \"mydoc\",\n      \"value\": null,\n      \"doc\": {\n        \"_id\": \"mydoc\",\n        \"_rev\": \"1-asd\",\n        \"foo\": \"bar\"\n      }\n    }\n  ]\n}\n```\nThis has no disadvantages performance wise, at least on PouchDB. For CouchDB it\nmeans additional lookups and prevents CouchDB from directly streaming the view\nresult from disk. But this is negligible. So don't emit the whole doc unless you\nneed the last bit of performance.\n\n\n### Linked Documents\nOr How do I do SQL-like JOINs? Can I avoid them?\n\nCouchDB (and PouchDB) supports [linked\ndocuments](https://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents).\nUse them to join two types of documents together, by simply adding an `_id` to the\nemitted value in the map function :\n\n```js\n// join artist data to albums\nfunction(doc) {\n  if (doc._id.match('^album:*')) {\n    emit(doc._id, null);\n    emit(doc._id, { '_id' : doc.artistId });\n  }\n}\n```\n\nWhen you query the view with the id of an album:\n\n```json\n{\n  \"include_docs\": true,\n  \"key\": \"album:hunkydory\"\n}\n```\n\nAnd this is a result:\n\n```json\n{\n  \"rows\": [\n    {\n      \"doc\": {\n        \"_id\": \"album:hunkydory\",\n        \"title\": \"Hunky Dory\",\n        \"year\": 1971,\n        \"artistId\": \"artist:david-bowie\"\n      },\n      \"id\": \"album:hunkydory\",\n      \"key\": \"album:hunkydory\"\n    }\n    {\n      \"doc\": {\n        \"_id\": \"artist:david-bowie\",\n        \"firstName\": \"David\",\n        \"lastName\": \"Bowie\"\n      },\n      \"id\": \"artist:david-bowie\",\n      \"key\": \"album:hunkydory\",\n      \"value\": {\n        \"_id\": \"artist:david-bowie\"\n      }\n    }\n  ]\n}\n```\n\nUsing linked documents can be a way to group together related data.\n\n\n### Built-In Reduce Functions\nCouchDB has some built in reduce functions to accomplish common tasks. They are\nnative and very performant. Choose them wherever possible.\nTo use a built in reduce, insert the name string instead of the function code,\neg\n\n```json\n{\n  \"views\": {\n    \"myview\": {\n      \"map\": \"function(doc) { emit(doc._id, 1) }\",\n      \"reduce\": \"_stats\"\n    }\n  }\n}\n```\n\n#### `_sum`\nAdds up the emitted values, which must be numbers.\n\n#### `_count`\nCounts the number of emitted values.\n\n#### `_stats`\nCalculates some numerical statistics on your emitted values, which must be\nnumbers.\nFor example:\n\n```json\n{\n  \"sum\": 80,\n  \"count\": 20,\n  \"min\": 1,\n  \"max\": 100,\n  \"sumsqr\": 30\n}\n```\n\n\n### Debugging Views\nView debugging can be a pain when you're restricted to Futon or even Fauxton.\nBy using [couchdb-view-tester](https://github.com/gr2m/couchdb-view-tester) you\ncan write view code in your preferred editor and watch the results in real time.\n\n\n### Testing Views\nUse [couchdb-ddoc-test](https://github.com/jo/couchdb-ddoc-test), a simple\nCouchDB design doc testing tool.\n\n```js\nvar DDocTest = require('couchdb-ddoc-test')\nvar test = new DDocTest({\n    fixture: {a: 1},\n      src: 'path/to/map.js'\n})\nvar result = test.runMap()\n\nassert.equals(result, fixture)\n```\n\n\n### Deploying Views\nYou want to keep your view code in VCS. Now you need a way to install the view\nfunction. You can use the [Python Couchapp\nTool](https://github.com/couchapp/couchapp). Its a CLI which reads a directory,\ncompiles documents from it and saves the documents in a CouchDB.\nSince this is a common task a quasi standard for the directory layout has been\nemerged, which is supported by a range of compatible tools.\nFor integration in JavaScript projects using a tool written in JavaScript avoids\nadditional dependencies. I wrote\n[couch-compile](https://github.com/jo/couch-compile) for that purpose. It reads\na directory, JSON file or node module and converts it into a CouchDB document,\nwhich can be deployed to a CouchDB database with\n[couch-push](https://github.com/jo/couch-push).\nThere is also a handy Grunt task,\n[grunt-couch](https://github.com/jo/grunt-couch) which integrates both projects\ninto the Grunt toolchain.\n\n\n### Modularize View Code\nWhile you work with views at some point you might want to share code between\nviews or simply break your code into smaller modules. For that purpose CouchDB\nhas [support for CommonJS\nmodules](http://docs.couchdb.org/en/1.6.1/query-server/javascript.html?highlight=commonjs#commonjs-modules),\nwhich you know from node.\nCouchDB implements [CommonJS 1.1.1](http://wiki.commonjs.org/wiki/Modules/1.1.1).\n\nTake this example:\n\n```js\nvar person = function(doc) {\n  if (!doc._id.match(/^person:/)) return\n  return {\n    name: doc.firstname + ' ' + doc.lastname,\n    createdAt: new Date(doc.created_at)\n  }\n}\n\nvar ddoc = {\n  _id: '_design/person',\n  views: {\n    lib: {\n      person: \"module.exports = \" + person.toString()\n    },\n    'people-by-name': {\n      map: function(doc) {\n        var person = require('views/lib/person')(doc)\n        if (!person) return\n        emit(person.name, null)\n      }.toString(),\n      reduce: '_count'\n    },\n    'people-by-created-at': {\n      map: function(doc) {\n        var person = require('views/lib/person')(doc)\n        if (!person) return\n        emit(person.createdAt.getTime(), null)\n      }.toString(),\n      reduce: '_count'\n    }\n  }\n}\n```\n\nCommonJS modules can also be used for shows, lists and validate\\_doc\\_update\nfunctions.\nNote that the `person` module is inside the `views` object. This is needed for\nCouchDB in order to detect changes on the view code.\nReduce functions *can NOT* use modules.\n\nRead more about [CommonJS modules in CouchDB](http://caolanmcmahon.com/posts/commonjs_modules_in_couchdb/).\n\n\n### View Collation\nView Collation basically just means the concept to query data by ranges, thus\nusing `startkey` and `endkey`. In CouchDB keys does not necessarily be strings,\nthey can be arbitrary JSON values. If thats the case we talk about _complex keys_.\n\nMaking use of View Collation enables us to query related documents together. Its\nthe CouchDB way of doing *joins*. See [Linked Documents](#linked-documents).\n\nComplex Keys order in the following matter:\n\n1. `null`, `false`, `true`\n2. `1`, `2`...\n3. `a`, `A`, `b`...`\\ufff0`\n4. `[\"a\"]`, `[\"b\"]`, `[\"b\",\"c\"]`\n5. `{}`, `{a:1}`, `{a:2}`, `{b:1}`\n\n\nRead more about this topic in [CouchDB\n\"Joins\"](http://www.cmlenz.net/archives/2007/10/couchdb-joins) by Christopher Lenz\nand in the [CouchDB docs about View\nCollation](https://docs.couchdb.org/en/latest/couchapp/views/collation.html)\n\n\n### Group Level\nConsider the follwing documents\n\n```json\n[\n  { \"_id\": \"1\", \"date\": \"2014-05-01T00:00:00.000Z\", \"temperature\": -10.00 },\n  { \"_id\": \"2\", \"date\": \"2015-01-01T00:00:00.000Z\", \"temperature\":  -7.00 },\n  { \"_id\": \"3\", \"date\": \"2015-02-01T00:00:00.000Z\", \"temperature\":  10.00 },\n  { \"_id\": \"4\", \"date\": \"2015-02-02T00:00:00.000Z\", \"temperature\":  11.00 },\n  { \"_id\": \"5\", \"date\": \"2015-02-02T01:00:00.000Z\", \"temperature\":  12.00 },\n  { \"_id\": \"6\", \"date\": \"2015-02-02T01:01:00.000Z\", \"temperature\":  12.20 },\n  { \"_id\": \"7\", \"date\": \"2015-02-02T01:01:01.000Z\", \"temperature\":  12.21 }\n]\n```\n\nAnd the map function:\n\n```js\nfunction(doc) {\n  var date = new Date(doc.date)\n\n  emit([\n    date.getFullYear(),\n    date.getMonth(),\n    date.getDay(),\n    date.getHours(),\n    date.getMinutes(),\n    date.getSeconds()\n  ], doc.temperature)\n}\n```\nAnd the build in reduce function `_stats`.\n\nWhen you not query the view you get the stats over all entries:\n\n```json\n{\n  \"rows\" : [\n    {\n      \"value\" : {\n        \"max\" : 12.21,\n        \"sumsqr\" : 811.9241,\n        \"count\" : 7,\n        \"sum\" : 40.41,\n        \"min\" : -10\n      },\n      \"key\" : null\n    }\n  ]\n}\n```\n\n`group_level=1` gives you\n\n```json\n{\n   \"rows\" : [\n      {\n         \"key\" : [\n            2014\n         ],\n         \"value\" : {\n            \"sumsqr\" : 100,\n            \"count\" : 1,\n            \"max\" : -10,\n            \"min\" : -10,\n            \"sum\" : -10\n         }\n      },\n      {\n         \"key\" : [\n            2015\n         ],\n         \"value\" : {\n            \"count\" : 6,\n            \"sumsqr\" : 711.9241,\n            \"min\" : -7,\n            \"max\" : 12.21,\n            \"sum\" : 50.41\n         }\n      }\n   ]\n}\n```\n\nUpto `group_level=7` (which is the same as `group=true`)\n\n```json\n{\n   \"rows\" : [\n      {\n         \"key\" : [\n            2014,\n            4,\n            4,\n            2,\n            0,\n            0\n         ],\n         \"value\" : {\n            \"max\" : -10,\n            \"count\" : 1,\n            \"sum\" : -10,\n            \"min\" : -10,\n            \"sumsqr\" : 100\n         }\n      },\n      ...\n      {\n         \"value\" : {\n            \"min\" : 12.21,\n            \"sum\" : 12.21,\n            \"sumsqr\" : 149.0841,\n            \"max\" : 12.21,\n            \"count\" : 1\n         },\n         \"key\" : [\n            2015,\n            1,\n            1,\n            2,\n            1,\n            1\n         ]\n      }\n   ]\n}\n```\n\nCombining this with key or range queries you can get all sort of fine grained stats.\n\n\n### Naming Conventions For Views\nNaming convention for views, starting from the basic case of no reduce functions.\nViews are couples of arbitrary functions, and as such it is impossible to express\ntheir whole variety with a name, so I am just trying to cover the most common cases.\n\n#### No Reduce\nIn the case of no reduce function, usually views are just meant to sort documents\nby a set of properties. An idea in this case is to name them like this:\n\nThe main grouping parameter for the name is the “object” as it (roughly) exists\nin the application space. For example: `person`, `contact`, `address` etc.:\n\n```\n<object>-\n```\n\nWhat follows is a condition for a subset of objects, e.g. `persons-with-address`:\n\n```\n<object>-with-<property>\n<object>-with-no-<property>\n```\n\nThen, there is a sort option, e.g. `persons-with-address-by-createddate`:\n\n```\n<option>-with-<property>-by-<sortfield>\n```\n\n`with` and `by` clauses are both optional.\n\nFinally, there is an optional suffix that describes whether the view emits the\nfull document as a value, e.g. `persons-with-address-fulldoc`: \n\n```\n<object>-with-<property>-fulldoc\n```\n\n\nWhen a property is nested, just replace the dot `.` with a dash `-`. Convert\ncases to lowercase. Convert underscore separated to no separation.\n\n\n##### Examples\nAll people documents:\n\n```\npeople\n```\n\nAll cases sorted by doc.lastModifiedDate:\n\n```\ncases-by-lastmodifieddate\n```\n\nAll addresses that have a city property sortedby `doc.createdDate`:\n\n```\naddress-with-city-by-createddate\n```\n\n#### With a reduce function\nIn this case, i would use the same convention, with a prefix expressing the reduce.\nThe reduce part could be structured as follows:\n\n```\n[count|sum|stats]-[on-<property>-]<map part>\n```\n\n##### Examples\n\n```\nstats-on-patient-age-by-case-status\n```\n\nThe case above refers to built-in reduce functions, which should cover the wide\nmajority of uses.\n\n\n\n## Replication\n\n### Filtered Replication\nFiltered replication is a great way limit the amount of data synchronized on a\ndevice.\n\nFilters can be by id (`_doc_ids`), by filter function, or by view (`_view`).\n\nBe aware that replication filters other than `_doc_ids` are very slow,\nbecause they run on *every* document. Consider writing those filter functions in\nErlang.\n\nWhen using filtered replication think about deleted documents, and whether they\npass the filter. One way is to filter by id (this might be an argument for keeping\n`type` in the id).  \nOr deletion can be implemented as an update with `_deleted: true`. That way data\nis still there and can be used in the filter.\n\n\n### Using Replication\nThere are two ways to start a replication: the `_replicator` database and the\n`_replicate` API endpoint.\nUse `_replicator` database when in doubt.\n\n#### `_replicate` API endpoint\nWhen you use Futon you use the replicator endpoint. To initiate a replication\npost a JSON:\n\n```json\n{\n  \"source\": \"a-db\",\n  \"target\": \"another-db\",\n  \"continuous\": true\n}\n```\n\nThe response includes a replication id (which can also be obtained from\n`_active_tasks`):\n\n```json\n{\n  \"ok\": true,\n  \"_local_id\": \"0a81b645497e6270611ec3419767a584+continuous\"\n}\n```\n\nHaving this id you can cancel a continuous replication by posting\n\n```json\n{\n  \"replication_id\": \"0a81b645497e6270611ec3419767a584+continuous\",\n  \"cancel\": true\n}\n```\nto the `_replicate` endpoint.\n\n#### `_replicator` Database\nReplications created via the `_replicator` database are persisted and survive a\nserver restart. Its just a normal database which means you have the default\noperations. Replications are initiated by creating replication documents:\n\n```json\n{\n  \"_id\": \"initial-replication:a-db:another-db\",\n  \"source\": \"a-db\",\n  \"target\": \"another-db\",\n  \"continuous\": true\n}\n```\nLook, you can have meaningful ids! Cancelling is straight forward - just delete\nthe document.\nRead [more about the `_replicator`\ndatabase](https://gist.github.com/fdmanana/832610).\n\n\n\n## Conflicts\n\n### Conflict Handling\nSome things need to and should be conflicts. CouchDB *conflicts are first class\ncitizens*, (or at least [should be treated\nas such](https://gist.github.com/rnewson/2387973#file-gistfile1-txt-L6)). If 2\ndifferent users enter different addresses for the same person at the same time,\nthat probably should create a conflict. Your best option is to have a conflict\nresolution daemon running on the server. While we don’t have this at the moment,\nlook at the\n[pouch-resolve-conflicts](https://github.com/jo/pouch-resolve-conflicts) plugin.\n\n\n\n## Deployment\n\n### CouchDB Behind A Proxy\nRunning CouchDB behind a proxy is recommended, e.g. to handle ssl termination.\n\n*Prefer subdomain over subdirectory*.  Nginx encodes urls on the way through.\nSo, for example, if you request\n`http://my.couch.behind.nginx.com/mydb/foo%2Fbar` it gets routed to CouchDB as\n`/mydb/foo/bar`, which is not what we want.\n\nWe can configure this mad behaviour away (by [not appending a slash to the\n`proxy_pass`\ntarget](http://stackoverflow.com/questions/20496963/avoid-nginx-decoding-query-parameters-on-proxy-pass-equivalent-to-allowencodeds)).\nBut there is no way to convince nginx not messing with the url when rewriting\nthe proxy behind a subdirectory, e.g.\n`http://my.couch.behind.nginx.com/_couchdb/mydb/foo%2Fbar`\n\n\n\n## Misc\n\n### Debugging PouchDB\nI often assign the database instance to window and then I run queries on it.\nOr you can replicate to a local CouchDB and debug your views there.\n\nIf you like PouchDB to be more verbose, [enable debug\noutput](http://pouchdb.com/api.html#debug_mode):\n\n```js\nPouchDB.debug.enable('*')\n```\n\n### PouchDB and AngularJS\nTo use PouchDB with AngularJS you should use\n[angular-pouchdb](https://github.com/angular-pouchdb/angular-pouchdb), which\nwraps PouchDBs promises with Angulars `$q`s.\n\nDebugging angular-pouchdb in a console can be done by first retrieving the\ninjector and calling the `pouchDB` service as normal, e.g.:\n\n```js\nvar pouchDB = angular.element(document.body).injector().get('pouchDB')\nvar db = pouchDB('mydb')\ndb.get('id').then()\n```\n\n### Full Text Search\nWhile basic full text search is possible just by using views, its not\nconvenient and you should make use of a dedicated FTI.\n\n#### Client Side\nFor PouchDB the situation is clear: Use [PouchDB Quick\nSearch](https://github.com/nolanlawson/pouchdb-quick-search). Its a PouchDB\nplugin based on [lunr.js](http://lunrjs.com/).\n\n#### Server Side\nOn a CouchDB server you have options: Lucene (via\n[couchdb-lucene](http://github.com/rnewson/couchdb-lucene)) or ElasticSearch via\n[The River](https://www.elastic.co/blog/the-river/). At eHealth Africa we use\nthe latter.\n\n\n### Two Ways of Deleting Documents\nThere are two ways to delete a document: via DELETE or by updating the document\nwith a `_deleted` property set to true:\n\n```json\n{\n  \"_id\": \"mydoc\",\n  \"_rev\": \"1-asd\",\n  \"type\": \"person\",\n  \"name\": \"David Foster Wallace\",\n  \"_deleted\": true\n}\n```\n\nIn either way the deleted document will stay in the database, even after\ncompaction. (That way the deletion can be propagated to all replicas.)\nUsing the manual variant allows you to keep data, which might be useful for\nfiltered replication or other purposes. Otherwise all properties will get removed\nexcept the plain stub:\n\n```json\n{\n  \"_id\": \"mydoc\",\n  \"_rev\": \"2-def\",\n  \"_deleted\": true\n}\n```\n\n---\n\n© 2015 [eHealth Africa][eha]. Written by [TF][] and [contributors][]. Released under the [Apache 2.0 License][license].\n\n[eha]: http://ehealthafrica.org\n[TF]: https://www.die-tf.de\n[contributors]: https://github.com/jo/couchdb-best-practices/graphs/contributors\n[license]: https://www.apache.org/licenses/LICENSE-2.0.html\n"
  },
  {
    "path": "_config.yml",
    "content": "markdown: redcarpet\nredcarpet:\n  extensions: [\"with_toc_data\"]\n"
  },
  {
    "path": "_layouts/default.html",
    "content": "<!DOCTYPE html>\n<html lang=en>\n<meta charset=utf-8>\n<title>CouchDB Best Practices</title>\n<meta name=description content=\"collect best practices around the CouchDB universe.\" />\n<meta name=viewport content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />\n<link href=css/syntax.css rel=stylesheet>\n<style>\n  body {\n    font-family: \"HelveticaNeue-Light\", Helvetica, Arial, sans-serif;\n    font-size: 16px;\n    line-height: 1.5;\n    margin: 3ex 0 0 0;\n    padding: 6.18% 10%;\n  }\n  \n  .headerbar {\n    position: fixed;\n    top: 0;\n    left: 0;\n    right: 0;\n    margin: 0;\n    max-width: none;\n    padding: 1ex 10%;\n    text-align: right;\n    background: white;\n  }\n  .headerbar a {\n    text-decoration: none;\n    margin-right: 1em;\n  }\n  .headerbar a:last-child {\n    margin-right: 0;\n  }\n\n  body, a {\n    color: #291D1E;\n  }\n  a:hover {\n    color: #F00;\n    transition: color 0.25s linear 0s;\n  }\n  p {\n    max-width: 42em;\n  }\n  h2 {\n    padding-top: 6ex;\n  }\n  h3 {\n    padding-top: 6ex;\n  }\n  h2 + h3 {\n    padding-top: 3ex;\n  }\n  h4 {\n    padding-top: 6ex;\n  }\n  h5 {\n    padding-top: 3ex;\n    margin-bottom: 0;\n    font-size: 0.8em;\n  }\n  h2:target:before,\n  h3:target:before,\n  h4:target:before {\n    content: '_';\n    margin-left: -0.618em;\n  }\n  hr {\n    border: none;\n    border-top: 1px solid black;\n    margin: 12ex -10% 0 -10%;\n    padding: 3ex 10% 0 10%;\n  }\n  blockquote {\n    font-style: italic;\n    font-size: 1.2em;\n    color: #725355;\n  }\n  .highlight {\n    margin: 1ex -10%;\n    padding: 1ex 10%;\n    background-color: #F7F7F7;\n    overflow: auto;\n  }\n</style>\n\n<p class=headerbar>\n  <a href=https://github.com/jo/couchdb-best-practices/edit/gh-pages/README.md>Edit</a>\n  <a href=https://github.com/jo/couchdb-best-practices/issues>Ask</a>\n  <a href=https://github.com/jo/couchdb-best-practices>Fork</a>\n</p>\n<main>\n  {{ content }}\n</main>\n<script src=js/anchor.min.js></script>\n<script>\n  anchors.options = {\n    placement: 'left'\n  }\n  anchors.add('main h2, main h3, main h4, main h4, main h5')\n  anchors.remove('h2 + h3')\n</script>\n"
  },
  {
    "path": "css/syntax.css",
    "content": ".highlight  { background: #ffffff; }\n.highlight .c { color: #999988; font-style: italic } /* Comment */\n.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */\n.highlight .k { font-weight: bold } /* Keyword */\n.highlight .o { font-weight: bold } /* Operator */\n.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */\n.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */\n.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #aa0000 } /* Generic.Error */\n.highlight .gh { color: #999999 } /* Generic.Heading */\n.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */\n.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #555555 } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #aaaaaa } /* Generic.Subheading */\n.highlight .gt { color: #aa0000 } /* Generic.Traceback */\n.highlight .kc { font-weight: bold } /* Keyword.Constant */\n.highlight .kd { font-weight: bold } /* Keyword.Declaration */\n.highlight .kp { font-weight: bold } /* Keyword.Pseudo */\n.highlight .kr { font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */\n.highlight .m { color: #009999 } /* Literal.Number */\n.highlight .s { color: #d14 } /* Literal.String */\n.highlight .na { color: #008080 } /* Name.Attribute */\n.highlight .nb { color: #0086B3 } /* Name.Builtin */\n.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */\n.highlight .no { color: #008080 } /* Name.Constant */\n.highlight .ni { color: #800080 } /* Name.Entity */\n.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */\n.highlight .nn { color: #555555 } /* Name.Namespace */\n.highlight .nt { color: #000080 } /* Name.Tag */\n.highlight .nv { color: #008080 } /* Name.Variable */\n.highlight .ow { font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mf { color: #009999 } /* Literal.Number.Float */\n.highlight .mh { color: #009999 } /* Literal.Number.Hex */\n.highlight .mi { color: #009999 } /* Literal.Number.Integer */\n.highlight .mo { color: #009999 } /* Literal.Number.Oct */\n.highlight .sb { color: #d14 } /* Literal.String.Backtick */\n.highlight .sc { color: #d14 } /* Literal.String.Char */\n.highlight .sd { color: #d14 } /* Literal.String.Doc */\n.highlight .s2 { color: #d14 } /* Literal.String.Double */\n.highlight .se { color: #d14 } /* Literal.String.Escape */\n.highlight .sh { color: #d14 } /* Literal.String.Heredoc */\n.highlight .si { color: #d14 } /* Literal.String.Interpol */\n.highlight .sx { color: #d14 } /* Literal.String.Other */\n.highlight .sr { color: #009926 } /* Literal.String.Regex */\n.highlight .s1 { color: #d14 } /* Literal.String.Single */\n.highlight .ss { color: #990073 } /* Literal.String.Symbol */\n.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */\n.highlight .vc { color: #008080 } /* Name.Variable.Class */\n.highlight .vg { color: #008080 } /* Name.Variable.Global */\n.highlight .vi { color: #008080 } /* Name.Variable.Instance */\n.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */\n"
  },
  {
    "path": "index.md",
    "content": "---\nlayout: default\n---\n\n{% include_relative README.md %}\n"
  }
]