{"_id":"markup-js","_rev":"44-84535e2a87f6e4eaccb9ed67dd771be8","name":"markup-js","description":"Markup.js - Powerful JavaScript Templates","dist-tags":{"latest":"1.5.21"},"versions":{"1.5.12":{"name":"markup-js","version":"1.5.12","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.12","dist":{"shasum":"af5843b12756ce47197abeaf85eaef868c2cae35","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.12.tgz","integrity":"sha512-1hBkIa0IxxJOGZGNGKV6H17meWnmAjqx5NrTNqijRJUVwVasjLCHhg6JzbmuolRf9A2MBx7Sva/1IC02m5vKPA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDeLO3XAMS3dE/GuoivUWA1qNlFfM8mixyI43yg9K39awIhAM34A93lFeIxKPvD5t9C51YR07u8DKIlN03VdiR3cRZK"}]},"_npmVersion":"1.1.59","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"directories":{}},"1.5.13":{"name":"markup-js","version":"1.5.13","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.13","dist":{"shasum":"ac227542d7be43e2a95aa4d5afa0a03bbdb439b1","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.13.tgz","integrity":"sha512-O3I7YB8N93fmCJicMB1KRLwzIVErGNr9a3UfX+w+xkaFmHmSpcQ2EHYV15yjahylIJbVWyEUrktxOCuSMp2Cvg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBjQZ2Qyek6HDxXYmk68QFy+7V0B5R4Vs3ZonouiR3rXAiBq6jb6TVPBW0rAY13PYPbUx5lo9/tkAZoKjo7zG1a2ng=="}]},"_npmVersion":"1.1.65","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"directories":{}},"1.5.14":{"name":"markup-js","version":"1.5.14","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.14","dist":{"shasum":"c4c9a289d9ca5af47f0e3d9899b7670ea4d787a5","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.14.tgz","integrity":"sha512-Gs869EWoZsTJrWGMVzB5yPdN0HCM08wLsba0Y5pP7XFTXZh7PmlLgZmxw6mhw6zwiZnJHW4UJTiTINxJuvdyBA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDwd9cXirUEgDnlBo4hiBT6nEq2fZK0RX+HGUq9FOV83wIgEIEPZLm24ZH2xBm4Ji+KHatWFmgffa8cpGEFMZ/Qr4M="}]},"_npmVersion":"1.1.59","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"directories":{}},"1.5.15":{"name":"markup-js","version":"1.5.15","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.15","dist":{"shasum":"e056dccaad95b7ad827ab1616e51b28b354aed75","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.15.tgz","integrity":"sha512-WuW+KGoF9RTmErqtAHwPPHgYy8bmyUPqondCk5ztU4BhiO6Caxe2RZJ1JcdkEFTWvqKcakK+RFAQ0lZbRQO5/A==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD6J0boHOySje3hxTO29OyDnr9j76DMXW8cCCu5zdB6RgIgHP5GP7uphfe0IMH7sKKrX6hyyMdOxuyoFG7pW1d30Pw="}]},"_npmVersion":"1.1.65","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"directories":{}},"1.5.16":{"name":"markup-js","version":"1.5.16","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.16","dist":{"shasum":"68486b61e022f24b49c9c1eeee51a1d7481ff81d","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.16.tgz","integrity":"sha512-y3mbFExLnJgTk9PVaGlv6qJshdUKm6bNvXL8T4ZXsYAVPOlSMaxq9UpXGXkPk4qf8JgH4IlXDTC4f29DIHyheQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC/WHkG3tV9Md/fNExzgSgAqsuupKyJSuaFPNIZFaYMagIgS6WoIVbJmdH5k/dmsri9BBkYX+lR1MCqJHfCEH/zmss="}]},"_npmVersion":"1.1.65","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"directories":{}},"1.5.17":{"name":"markup-js","version":"1.5.17","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.17","dist":{"shasum":"f05bcf60fae017260738b6879b5a981fab2818fc","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.17.tgz","integrity":"sha512-rgGqQ4fkTR+bcL88POHW8C1cTwJWmGU1g+V43buB/2dLMECEHxjsCUsHpasz3auY5xOpye8nRr795LKUcuZ/4g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCv7PBH0oem9Pqi486eezuge/0W2RSgMDEauV8j2Y1rcwIgaYcMLgfE1q3IBAwI/9idDEnh8IKMmCP5RRfowhozkcc="}]},"_npmVersion":"1.1.65","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}]},"1.5.18":{"name":"markup-js","version":"1.5.18","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.18","dist":{"shasum":"6164984896659a29ba569598bda469b4365b073a","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.18.tgz","integrity":"sha512-PW08lY4JMlxR/ZeX84vgpMG3sXriyltgrakfeIP9WaZXo6Lu1YqSZNk1NIRCaf2/5GUlFcQKLwaeMWOUUY9P2Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE6hAHIXJLRQHK3V/V+t7u2zgmB/tLp83tiGv8g9EgQIAiEA0GJVXpBz0RHLnPl7CRpFmMzqZrbIJfg21K3G0iWHFnY="}]},"_from":".","_npmVersion":"1.2.15","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}]},"1.5.19":{"name":"markup-js","version":"1.5.19","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.19","dist":{"shasum":"067b2095c8282a508fcb5cfca2fa2616e525bf4e","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.19.tgz","integrity":"sha512-FObnYPOOfIes7IaRH9ENUFv8KJMJym2vOrFmR6EHzEhnCkRsnC9J5VfGOpAB627eN2ad++E4DcvK2jYY2paXkw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID8M8a3zb+vGNxkU12ZOGEaEanbjpgTI/d6yIUywDt2oAiBmKmqYiayAiEPKNHJePHFjQk5TqfU4C1uuM73+ZSb1bw=="}]},"_from":".","_npmVersion":"1.4.3","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}]},"1.5.20":{"name":"markup-js","version":"1.5.20","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.20","dist":{"shasum":"632a88b777b4e1a4db89e9cf4109c6a1cdf16afa","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.20.tgz","integrity":"sha512-8SVomD8RhBh4uuYIYq03SnasV2BfV4aDTo1ULQF0PXpON4pzqhIvqK0izL6Rb/kVl28ti1KxjMB+rWs4myJMrw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCDVhoxOd6XAAFYfYm/UoSew5+bGvb6NGkk5tzeaQbEDQIgE2M6rhzkohtRbDqMKdaUKBNtm5t9yAwc0zjiFYloyRM="}]},"_from":".","_npmVersion":"1.4.3","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}]},"1.5.21":{"name":"markup-js","version":"1.5.21","description":"Markup.js - Powerful JavaScript Templates","homepage":"https://github.com/adammark/Markup.js","author":{"name":"Adam Mark"},"files":["src/markup.js","src/markup.min.js","README.md"],"keywords":["markup","template","templating","html"],"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"main":"./src/markup.js","bin":{"markup-js":"./src/markup.js"},"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"_id":"markup-js@1.5.21","dist":{"shasum":"389128703a565964574d0e357e142add3be46d79","tarball":"https://registry.npmjs.org/markup-js/-/markup-js-1.5.21.tgz","integrity":"sha512-qeUHSSwdXkcdGJv/Gd8s5l9jLEWIW5NwXDMkGkW8V1TSckB5IOdpZ/eIVzfiAOnAJU0brrSwVx6K2Ie86KGIXg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCb1TSz2rG9l8NCgIgWLbBRVqlg/+u8vYWB8RWEQ0rmuwIgQctqxspZcW2XGA3BI6oTTopRQZOeJzk5U6+U5nMonnE="}]},"_from":".","_npmVersion":"1.4.3","_npmUser":{"name":"adammark","email":"adammark75@gmail.com"},"maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}]}},"readme":"# Markup.js — Powerful JavaScript templates\n\nMarkup.js is a simple yet surprisingly powerful template system for\nJavaScript.\n\n## Why Markup.js?\n\nMarkup.js takes the pain out of converting structured data into HTML markup or\nother text formats. Its intuitive syntax and small footprint (only 1.9KB\nminified and gzipped) make it the perfect choice for your JavaScript app. Plus\nthere are *no dependencies.*\n\n## Usage\n\nInclude `<script src=\"markup.min.js\"></script>`.\n\nMarkup.js has a single function: `Mark.up(template, context)`. Here's a basic\nexample that shows how `template`, a string, is injected with properties of\n`context`, an object:\n\n``` javascript\nvar context = {\n    name: {\n        first: \"John\",\n        last: \"Doe\"\n    }\n};\n\nvar template = \"Hi, {{name.first}}!\";\n\nvar result = Mark.up(template, context); // \"Hi, John!\"\n```\n\nYou can format any kind of objects, including functions with exposed\nproperties:\n\n``` javascript\nvar context = {\n    person: new Person(\"Adam\")\n};\n\nvar template = \"Hi, {{person.name}}!\";\n\nvar result = Mark.up(template, context); // \"Hi, Adam!\"\n```\n\n## Object notation\n\nYou can access object properties with simple dot notation:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    addr: {\n        street: \"1 Maple Street\",\n        city: \"Pleasantville\",\n        zip: {\n            main: \"12345\",\n            ext: \"6789\"\n        }\n    }\n};\n\nvar template = \"{{name}} lives at {{addr.street}} in {{addr.city}}.\";\n\nvar result = Mark.up(template, context);\n// \"John Doe lives at 1 Maple Street in Pleasantville.\"\n```\n\nOr you can use nested tags:\n\n``` javascript\nvar template = \"{{name}} lives at {{addr}}{{street}} in {{city}}.{{/addr}}\";\n\nvar result = Mark.up(template, context);\n// \"John Doe lives at 1 Maple Street in Pleasantville.\"\n```\n\nOr you can use a combination of nested tags and dot notation:\n\n``` javascript\nvar template = \"ZIP: {{addr}}{{zip.main}}-{{zip.ext}}{{/addr}}\";\n\nvar result = Mark.up(template, context);\n// \"ZIP: 12345-6789\"\n```\n\n## Array notation\n\nArray members can be accessed by index. For example:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    colors: [\"Red\", \"Blue\", \"Green\"]\n};\n\nvar template = \"Favorite color: {{colors.0}}\";\n\nvar result = Mark.up(template, context);\n// \"Favorite color: Red\"\n```\n\nYou can mix array index notation and object property notation in the same\nexpression:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    friends: [{name: \"Bob\"}, {name: \"Fred\"}]\n};\n\nvar template = \"Best friend: {{friends.0.name}}\";\n\nvar result = Mark.up(template, context);\n// \"Best friend: Bob\"\n```\n\n## Loops\n\nIf a tag resolves to an array, the array is iterated. A single dot refers to\nthe current iteration context:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    brothers: [\"Jack\", \"Joe\", \"Jim\"]\n};\n\nvar template = \"<ul>{{brothers}}<li>{{.}}</li>{{/brothers}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>Jack</li><li>Joe</li><li>Jim</li></ul>\"\n```\n\n``` javascript\nvar context = {\n    user: {\n        contacts: [\"John\", \"Jane\"]\n    }\n};\n\nvar template = \"<ul>{{user.contacts}}<li>{{.}}</li>{{/user.contacts}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>John</li><li>Jane</li></ul>\"\n```\n\nWhen looping through an array of objects, object properties can be\nreferenced by name:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    sisters: [{name: \"Jill\"}, {name: \"Jen\"}]\n};\n\nvar template = \"<ul>{{sisters}}<li>{{name}}</li>{{/sisters}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>Jill</li><li>Jen</li></ul>\"\n```\n\nDot notation works inside loops as well:\n\n``` javascript\nvar context = {\n    sisters: [\n        {name: {first: \"Jill\", last: \"Doe\"}},\n        {name: {first: \"Jen\", last: \"Doe\"}}\n    ]\n};\n\nvar template = \"<ul>{{sisters}}<li>{{name.first}}</li>{{/sisters}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>Jill</li><li>Jen</li></ul>\"\n```\n\n### Loop counters\n\nInside a loop, a single hash sign refers to the current iteration index\n(0...n-1) and a double hash sign refers to the current iteration count\n(1...n):\n\n``` javascript\nvar template = \"{{sisters}} {{#}}-{{name.first}} {{/sisters}}\";\n// \" 0-Jill  1-Jen \"\n```\n\n``` javascript\nvar template = \"{{sisters}} {{##}}-{{name.first}} {{/sisters}}\";\n// \" 1-Jill  2-Jen \"\n```\n\nThis is useful for applying conditional formatting, as described below, and\nfor creating numbered lists.\n\n## Pipes\n\nPipes are a powerful way to transform variables. Here's a simple example:\n\n``` javascript\nvar context = {\n    name: \"John Doe\",\n    alias: \" J-Do \",\n    phone: null,\n    gender: \"male\",\n    age: 33.33,\n    vitals: [68, 162.5, \"AB\"],\n    brothers: [\"Jack\", \"Joe\", \"Jim\"],\n    sisters: [{name: \"Jill\"}, {name: \"Jen\"}],\n    jiggy: true\n};\n\nvar template = \"Name: {{name|upcase}}\";\n\nvar result = Mark.up(template, context);\n// \"Name: JOHN DOE\"\n```\n\nA pipe can accept arguments. For example, the `blank` pipe accepts a value to\ndisplay if the piped input is null or empty:\n\n``` javascript\nvar template = \"Phone: {{phone|blank>N/A}}\";\n\nvar result = Mark.up(template, context);\n// \"Phone: N/A\"\n```\n\nThe `choose` pipe accepts two strings and returns one of them depending on\nwhether the piped input is true or false:\n\n``` javascript\nvar template = \"John is jiggy: {{jiggy|choose>Yes>No}}\";\n\nvar result = Mark.up(template, context);\n// \"John is jiggy: Yes\"\n```\n\nPipes can be applied to any kind of data structure:\n\n``` javascript\n// get the second value in an array and round it\nvar template = \"Weight: {{vitals.1|round}} lbs.\";\n\nvar result = Mark.up(template, context);\n// \"Weight: 163 lbs.\"\n```\n\n``` javascript\n// sort an array of strings, then upcase each string\nvar template = \"<ul>{{brothers|sort}}<li>{{.|upcase}}</li>{{/brothers}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>JACK</li><li>JIM</li><li>JOE</li></ul>\"\n```\n\n``` javascript\n// reverse an array of objects, then chop each name property\nvar template = \"<ul>{{sisters|reverse}}<li>{{name|chop>2}}</li>{{/sisters}}</ul>\";\n\nvar result = Mark.up(template, context);\n// \"<ul><li>Je...</li><li>Ji...</li></ul>\"\n```\n\n### Chaining pipes\n\nVariables can be passed through multiple pipes. Here are two simple examples:\n\n``` javascript\nvar template = \"Alias: {{alias|trim|downcase}}\";\n\nvar result = Mark.up(template, context);\n// \"Alias: j-do\"\n```\n\n``` javascript\nvar template = \"Age: {{age|more>75|choose>Oldish>Youngish}}\";\n\nvar result = Mark.up(template, context);\n// \"Age: Youngish\"\n```\n\nYou can get very creative with pipes:\n\n``` javascript\nvar template = \"Bros: {{brothers|sort|limit>2|join> & }}\";\n\nvar result = Mark.up(template, context);\n// \"Bros: Jack & Jim\"\n```\n\n### Built-in pipes\n\nMarkup.js comes with more than 40 built-in pipes:\n\n`empty` (obj): Test for an empty array, empty string, null, undefined, or 0. `{{if apples|empty}}`\n\n`notempty` (obj): Test for the presence of a value. `{{if apples|notempty}}` or simply `{{if apples}}`\n\n`more` (obj, n): Test if a number, [iterator][1], or array is greater than n. `{{if articles|more>100}}` `{{if #|more>10}}`\n\n`less` (obj, n): Test if a number, [iterator][1], or array is less than n. `{{if age|less>21}}`\n\n`ormore` (obj, n): Test if a number, [iterator][1], or array is greater than or equal to n. `{{if age|ormore>18}}`\n\n`orless` (obj, n): Test if a number, [iterator][1], or array is less than or equal to n. `{{if age|orless>55}}`\n\n`between` (obj, n1, n2): Test if a number, [iterator][1] or array is between n1 and n2, inclusive. `{{if age|between>18>35}}`\n\n`equals` (obj, str): Test for equality (==). `{{if name|equals>Adam}}` `{{if age|equals>35}}`\n\n`notequals` (obj, str): Test for inequality (!=). `{{if name|notequals>Adam}}`\n\n`like` (str, str): Test for a pattern match (case-insensitive). `{{if name|like>Adam}}` `{{if name|like>a.*}}`\n\n`notlike` (str, str): Test for a non-match (case-insensitive). `{{if name|notlike>Adam}}`\n\n`blank` (str, str): Display a default value for a null or empty string. `{{title|blank>Untitled}}`\n\n`upcase` (str): Upper-case a string. `{{name|upcase}}`\n\n`downcase` (str): Lower-case a string. `{{name|downcase}}`\n\n`capcase` (str): Capitalize the first letter in each word. `{{title|capcase}}`\n\n`chop` (str, n): Chop a string to n chars followed by \"...\" if n < string length. `{{description|chop>100}}`\n\n`tease` (str, n): Chop a string to n words followed by \"...\" if n < word count. `{{summary|tease>15}}`\n\n`trim` (str): Trim leading and trailing white space from a string. `{{article|trim}}`\n\n`pack` (str): Trim and normalize white space in a string. `{{article|pack}}`\n\n`round` (num): Round a number. `{{age|round}}`\n\n`clean` (str): Strip HTML/XML tags from a string. `{{article|clean}}`\n\n`length` (obj): Get the length of an array, string, or [iterator][1]. `{{apples|length}}` `{{#|length}}`\n\n`size` (obj): Alias of length. `{{apples|size}}` `{{#|size}}`\n\n`reverse` (arr): Reverse an array.\\* `{{articles|reverse}} ... {{/articles}}`\n\n`join` (arr [, str]): Join an array with \",\" or with the given token. `{{names|join> + }}`\n\n`limit` (arr, n1 [, n2]): Limit an array to n1 items beginning at index n2 (or 0). `{{contacts|limit>10}} ... {{/contacts}}`\n\n`split` (str [, str]): Split a string on \",\" or by the given token. `{{names|split>;}} {{.}} {{/names}}`\n\n`choose` (bool, str [, str]): Output one value if truthy, another if falsy. `{{user.passed|choose>Pass>Fail}}`\n\n`toggle` (obj, str, str [,str]): Switch one string value for another. `{{gender|toggle>M,F>Boy,Girl>N/A}}`\n\n`sort` (arr [, str]): Sort an array, optionally by object property name.\\* `{{users|sort>firstname}} ... {{/users}}`\n\n`fix` (num, n): Format a number to n decimal places. `{{weight|fix>1}}`\n\n`mod` (num, n): Get the remainder of a number or [iterator][1] divided by n. `{{rows|mod>10}}`\n\n`divisible` (num, n): Test if a number or [iterator][1] is perfectly divisible by n. `{{if #|divisible>3}}`\n\n`even` (num): Test if a number or [iterator][1] is even. `{{if #|even}}`\n\n`odd` (num): Test if a number or [iterator][1] is odd. `{{if #|odd}}`\n\n`number` (str): Extract a number from a string (e.g. \"$1,234.56\" or \"30px\"). `{{price|number}}`\n\n`url` (str): URL-encode a string. `{{article.link|url}}`\n\n`bool` (obj): Cast an object to a boolean value. `{{user.geo_pref_flag|bool}}`\n\n`falsy` (obj): Test for falseness. `{{if expired|falsy}}`\n\n`first` (iterator): Test if an [iterator][1] is first. `{{if #|first}}`\n\n`last` (iterator): Test if an [iterator][1] is last. `{{if #|last}}`\n\n`call` (obj, func [, arg1, arg2, ...]): Call an object function. ([See doc below](#the-call-pipe)) `{{doggy|call>bark>5}}`\n\n`set` (obj, str): Set a variable for later use, outputting nothing. ([See doc below](#the-set-pipe)) `{{user.birthday|set>bday}}`\n\n`log` (obj): Log any variable to the console. ([See doc below](#logging)) `{{article.title|log}}`\n\n\\* Source array is not modified.\n\n### The 'call' pipe\n\nThe `call` pipe lets you call a function on any object and pass it zero or\nmore arguments:\n\n``` javascript\nvar context = {\n    num: 1.23\n};\n\nvar template = \"{{num|call>toPrecision>5}}\";\n\nvar result = Mark.up(template, context);\n// \"1.2300\"\n```\n\n``` javascript\nfunction Dog() {\n    var greeting = \"Woof!\";\n\n    this.bark = function (times) {\n        ...\n    };\n}\n\nvar context = {\n    doggy: new Dog()\n};\n\nvar template = \"{{doggy|call>bark>3}}\";\n\nvar result = Mark.up(template, context);\n// \"Woof! Woof! Woof!\"\n```\n\n### Writing custom pipes\n\nYou can add your own pipes to Markup.js. A pipe is simply a function with one\nor more arguments. The first argument (required) is the piped value itself.\nAny additional arguments are strings. For example:\n\n``` javascript\nMark.pipes.shout = function (str, n) {\n    return str + new Array(parseInt(n || 1) + 1).join(\"!\");\n};\n\nvar template = \"{{exclamation|shout>5}}\";\n\nvar result = Mark.up(template, { exclamation: \"Bonsai\" });\n// \"Bonsai!!!!!\"\n```\n\nIf you prefer, you can pass pipes into the optional `options` argument of\n`Mark.up`:\n\n``` javascript\nvar options = {\n    pipes: {\n        mypipe: function (str) { ... }\n    }\n};\n\nvar result = Mark.up(template, context, options);\n```\n\nNote! All _optional_ pipe arguments are passed as strings. For example, in \nthe expression `{{num|add>23>45}}`, \"23\" and \"45\" are strings. Therefore, \nyou should cast data types as necessary in your custom pipes:\n\n``` javascript\n// WRONG! 1 + \"23\" + \"45\" returns \"12345\"\nMark.pipes.add = function (a, b, c) {\n    return a + b + c;\n};\n\n// RIGHT! 1 + \"23\" + \"45\" returns 69\nMark.pipes.add = function (a, b, c) {\n    return a + parseInt(b) + parseInt(c);\n};\n```\n\n### Changing the argument delimiter\n\nYou can change the argument delimiter from \">\" to a character (or characters)\nof your choosing:\n\n``` javascript\nMark.delimiter = \":\";\n```\n\nThe delimiter can also be set in the optional `options` argument of `Mark.up`:\n\n``` javascript\nvar options = {\n    delimiter: \":\"\n};\n\nvar result = Mark.up(template, context, options);\n```\n\n### More pipes!\n\nAdditional pipes are available in `src/extras` for your piping pleasure. \n(These are not included in markup.js.)\n\n## IF and IF/ELSE statements\n\nIF statements are formatted as `{{if expression}} ... {{/if}}`, where\n*expression* is a boolean test with optional pipes:\n\n``` javascript\nvar template = \"{{if brothers}} John has {{brothers|size}} brothers! {{/if}}\"\n```\n\n``` javascript\nvar template = \"{{if children|empty}} John has no kids. {{/if}}\"\n```\n\n``` javascript\nvar template = \"{{if age|more>75}} John is a ripe old {{age|round}}! {{/if}}\"\n```\n\n``` javascript\nvar template = \"{{if age|between>50>75}} John is middle aged. {{/if}}\"\n```\n\nIF/ELSE statements work as you would expect:\n\n``` javascript\nvar template = \"{{if speed|more>65}} Too fast! {{else}} Too slow! {{/if}}\"\n```\n\nPipes can be chained in IF statements, allowing for arbitrarily complex\nexpressions:\n\n``` javascript\n// test if weight in kgs is greater than 500\nvar template = \"{{if weight|kgs|more>500}} Lighten up! {{/if}}\"\n```\n\nIF and IF/ELSE statements work the same way inside loops:\n\n``` javascript\n// show only users with email addresses\nvar template = \"{{users}} {{if email}} ... {{/if}} {{/users}}\";\n```\n\nIF and IF/ELSE statements can be nested:\n\n``` javascript\nvar template = \"{{if age|more>100}} {{if gender|equals>male}} Old man! {{/if}} {{/if}}\";\n```\n\n``` javascript\nvar template = \"{{if ...}} ... {{else}} {{if ...}} ... {{else}} ... {{/if}} {{/if}}\";\n```\n\n### Testing loop counters\n\nYou can use loop counters (# and ##) to apply conditional formatting:\n\n``` javascript\n// show different content in even and odd rows\nvar template = \"{{users}} {{if #|even}} ... {{else}} ... {{/if}} {{/users}}\";\n```\n\n``` javascript\n// print a table header every five rows starting at zero\nvar template = \"{{users}} {{if #|divisible>5}} <thead>...</thead> {{/if}} ... {{/users}}\";\n```\n\n``` javascript\n// print a table header every three rows after the tenth row\nvar template = \"{{users}} {{if ##|more>10|divisible>3}} <thead>...</thead> {{/if}} ... {{/users}}\";\n```\n\nCertain pipes can be used to evaluate the position of the current iteration\ncontext or the size of the array itself. In these cases, # and ## are\ninterchangeable:\n\n``` javascript\n// do something on the first iteration\nvar template = \"{{users}} {{if #|first}} ... {{/if}} ... {{/users}}\";\n```\n\n``` javascript\n// do something on the last iteration\nvar template = \"{{users}} {{if #|last}} ... {{/if}} ... {{/users}}\";\n```\n\n``` javascript\n// test the size of the array during the loop\nvar template = \"{{users}} {{if #|size|more>100}} ... {{/if}} ... {{/users}}\";\n```\n\n### Pipes in conditional expressions\n\nBoolean pipes, such as `between` or `more`, return the *inputted value* if the\nexpression is true. Otherwise they return *false*. This way, pipes can be\nchained together to form complex AND statements. For example:\n\n``` javascript\n// a custom pipe\nMark.pipes.big = function (num) {\n    return num > 1000000 ? num : false;\n};\n\nvar context = { salary: 5000000 };\n\nvar template = \"{{if salary|big|even}} A nice round number! {{/if}}\";\n```\n\nIn the above example, `salary|big|even` returns *5000000*, which resolves to\n*true*. *You should follow this convention if you write boolean pipes.*\n\n## Includes\n\nYou can include templates inside other templates. For example:\n\n``` javascript\nMark.includes.greeting = \"My name is {{name|upcase}}!\";\n\nvar template = \"Hello! {{greeting}}\";\n\nvar result = Mark.up(template, context);\n// \"Hello! My name is JOHN DOE!\"\n```\n\nYou can even pipe the output of an included template:\n\n``` javascript\nvar template = \"Hello! {{greeting|upcase}}\";\n\nvar result = Mark.up(template, context);\n// \"Hello! MY NAME IS JOHN DOE!\"\n```\n\nAs with custom pipes, includes can be passed into the optional `options`\nargument of `Mark.up`:\n\n``` javascript\nvar options = {\n    pipes: {\n        repeat: function () { ... }\n    },\n    includes: {\n        header: \"<div> ... </div>\",\n        footer: \"<div> ... </div>\"\n    }\n};\n\nvar result = Mark.up(template, context, options);\n```\n\n### Functions as includes\n\nYou can even include a *function* that returns a string when the template is\nprocessed:\n\n``` javascript\nMark.includes.status = function () {\n    return \"You are here: \" + location.href;\n};\n\nvar template = \"Welcome! {{status}}\";\n\nvar result = Mark.up(template, context);\n// \"Welcome! You are here: http://www.example.com/\"\n```\n\n*Includes are accessible in the global scope of template execution and from\none template to another. They take precedence over `context` variables with\nthe same name, so be careful to avoid naming conflicts.*\n\n## Global variables\n\nYou can create global variables for use anywhere inside a template. For\nexample:\n\n``` javascript\nMark.globals.img_width = 200;\n\nvar template = \"{{images}} <img width='{{img_width}}'/> {{/images}}\";\n```\n\nA global variable can be any kind of object. As with includes, global\nvariables can be passed into the optional `options` argument of `Mark.up`:\n\n``` javascript\nvar options = {\n    globals: {\n        img_width: 200,\n        img_height: 300\n    }\n};\n\nvar result = Mark.up(template, context, options);\n```\n\n### The 'set' pipe\n\nThe special `set` pipe lets you set a global variable *inside the template itself*:\n\n``` text\n{{users|size|set>num_users}}\n\n{{if num_users|more>10}}\n    ...\n{{/if}}\n```\n\n*Global variables are accessible from one template to another. They take\nprecedence over includes and `context` variables with the same name, so be \ncareful to avoid naming conflicts.*\n\n## Backtick expressions\n\nAlthough it's rarely necessary, you might want to pass a context variable as\nan argument to a pipe. You can do this by enclosing the variable in backticks:\n\n``` javascript\nvar context = {\n    \"name\": \"John\",\n    \"age\": 50,\n    \"retirement_age\": 55\n};\n\nvar template = \"{{if age|more>`retirement_age`}} Life of leisure {{/if}}\";\n```\n\nThe statement within backticks can be a fully qualified expression, as in:\n\n``` text\n{{if age|more>`spouse.age|times>2`}} Ewwwwww {{/if}}\n```\n\nThis technique also applies to global variables:\n\n``` text\n{{user.prefs.colors.0|set>favorite_color}}\n\n{{if other_color|equals>`favorite_color`}} Match! {{/if}}\n```\n\nAs a best practice, business logic should stay in the business layer of your\napplication. Compare the readability of the following expressions:\n\n``` text\n{{if user.age|more>`user.retirement_age`}}\n\n{{if user.retired}}\n```\n\n## White space\n\nSometimes it's convenient to remove all white space between HTML or XML nodes\nin the final output. For example, you might want `<div>A</div> <div>B</div>`\nto become `<div>A</div><div>B</div>`. To remove white space:\n\n``` javascript\nMark.compact = true;\n```\n\nOr, via the `options` argument:\n\n``` javascript\nvar options = {\n    compact: true\n};\n\nvar result = Mark.up(template, context, options);\n```\n\n## Logging\n\nYou can log any variable to the console for debugging purposes with the `log` \npipe:\n\n``` text\n<!-- logs \"LION\" \"TIGER\" \"BEAR\" -->\n{{animals}}\n    {{name|upcase|log}}\n{{/animals}}\n\n<!-- logs \"lion\" \"tiger\" \"bear\" -->\n{{animals}}\n    {{name|log|upcase}}\n{{/animals}}\n```\n\n## Gotchas\n\nHere are some common traps to avoid:\n\n### Ambiguous templates\n\nThe following template is ambiguous because the first tag is unclosed:\n\n``` javascript\nvar template = \"Adam has {{bros|length}} brothers: {{bros}}...{{/bros}}\";\n```\n\nIn such cases, you should use a self-closing tag:\n\n``` javascript\nvar template = \"Adam has {{bros|length /}} brothers: {{bros}}...{{/bros}}\";\n```\n\n### Incorrect notation\n\nMarkup.js uses dot notation, not bracket notation, for both objects and\narrays:\n\n``` javascript\nvar context = {\n    name: { first: \"John\", last: \"Doe\" },\n    colors: [\"Red\", \"Blue\", \"Green\"]\n};\n\n// WRONG\nvar template = \"First name: {{name[first]}}\";\n\n// RIGHT\nvar template = \"First name: {{name.first}}\";\n\n// WRONG\nvar template = \"Favorite color: {{colors[0]}}\";\n\n// RIGHT\nvar template = \"Favorite color: {{colors.0}}\";\n```\n\n### Use of quote marks in pipes\n\nMarkup.js treats all piped variables as strings, so quote marks are treated \nlike any other characters:\n\n``` javascript\n// WRONG\nvar template = \"{{if name|like>'Adam'}} ...\";\n\n// RIGHT\nvar template = \"{{if name|like>Adam}} ...\";\n```\n\n## Browser implementation\n\nYou can implement Markup.js in a few different ways. The right strategy\ndepends on many factors, including the speed and size of your app, the number\nof templates you're handling, and whether you want the templates to be\nreusable throughout your codebase.\n\n### 1. Writing templates as JavaScript strings\n\nYou can write templates as JavaScript string literals, as shown above.\nIt's a good idea to put all your templates together in one file:\n\n``` javascript\n// templates.js\nmyapp.templates = {\n    user_details: \"<div> ... </div>\",\n    user_sidebar: \"<div> ... </div>\"\n};\n```\n\nAs your app grows, you might consider splitting up your templates by\nfunctional area and loading only some of them at a time:\n\n``` javascript\n// templates-registration.js\nmyapp.templates.registration = {\n    reg_intro: \"<div> ... </div>\",\n    reg_error: \"<div> ... </div>\"\n};\n\n// templates-cart.js\nmyapp.templates.cart = {\n    cart_proceed: \"<div> ... </div>\",\n    cart_cancel: \"<div> ... </div>\"\n};\n```\n\nYou can use jQuery to inject an evaluated template into a document element:\n\n``` javascript\nvar template = myapp.templates.user_sidebar;\n\nvar context = user.data;\n\n$(\"#sidebar\").html(Mark.up(template, context));\n```\n\nOr, without jQuery:\n\n``` javascript\ndocument.getElementById(\"sidebar\").innerHTML = Mark.up(template, context);\n```\n\n### 2. Embedding templates in &lt;script&gt; tags\n\nThe above method can be unwieldy if you're dealing with large chunks of HTML.\nInstead, you might want to embed templates inside `<script>` tags:\n\n``` text\n<!-- people.html -->\n...\n<script id=\"persons-list\" type=\"text/template\">\n    <h1>People</h1>\n    <ul>\n        {{persons|sort>lastName}}\n            <li>{{lastName}}, {{firstName}}</li>\n        {{/persons}}\n    </ul>\n</script>\n...\n```\n\nThen extract the template from the `<script>` tag:\n\n``` javascript\nvar template = document.getElementById(\"persons-list\").firstChild.textContent;\n```\n\nBe sure to specify `type=\"text/template\"` on the script tag or else browsers\nwill interpret the contents as JavaScript.\n\n### 3. Loading templates with AJAX\n\nThe above method makes it easier to write templates but harder to reuse them\nthroughout your app. A compromise solution is to write your templates in plain\ntext files and load them via AJAX. Here's how to do it with jQuery:\n\n``` javascript\n$.get(\"user-template.txt\", function (txt) {\n    // do stuff\n}, \"html\");\n```\n\nTo reduce the number of network requests, you can put multiple templates in a\nsingle text file:\n\n``` text\n===== user_detail\n<div class=\"user-details\">\n    ...\n</div>\n\n===== user_profile\n<div class=\"user-profile\">\n    ...\n</div>\n```\n\nThen load and parse the file:\n\n``` javascript\nvar templates = {};\n\n$.get(\"user-templates.txt\", function (text) {\n    var chunks = text.split(\"=====\").splice(1);\n    var i, key;\n \n    chunks.forEach(function (chunk) {\n        i = chunk.indexOf(\"\\n\");\n        key = chunk.substr(0, i).trim();\n        templates[key] = chunk.substr(i).trim();\n    });\n\n}, \"html\");\n```\n\nYou can also cache templates in [Local Storage](http://diveintohtml5.info/storage.html) \nor the [Application Cache](http://www.html5rocks.com/en/tutorials/appcache/beginner/) \nfor instantaneous retrieval.\n\n## Server implementation\n\nYou can install Markup.js as a [Node.js package](https://npmjs.org/package/markup-js):\n\n```\n$ npm install markup-js\n```\n\nThen require `markup-js` and load your templates from the file system:\n\n``` javascript\nvar Mark = require(\"markup-js\"),\n    fs = require(\"fs\");\n\n// load asynchronously\nfs.readFile(\"some-template.txt\", \"utf8\", function (err, data) {\n    var template = data;\n    ...\n});\n\n// or load synchronously\nvar template = fs.readFileSync(\"some-template.txt\", \"utf8\");\n```\n\n## Internationalization (i18n)\n\nMarkup.js can support internationalization of your UI. Here's a basic approach\nto creating a resource \"bundle\" for each target language:\n\n``` javascript\n// english\nvar resources = {\n    hello_msg: \"Hi, {{user.name}}.\",\n    goodbye_msg: \"Bye, {{user.name}}.\"\n};\n```\n\n``` javascript\n// spanish\nvar resources = {\n    hello_msg: \"Hola, {{user.name}}.\",\n    goodbye_msg: \"Adios, {{user.name}}.\"\n};\n```\n\nYou can load the appropriate bundle with a \n[conditional script loader](http://microjs.com/#loader) or other mechanism.\n\nAlternatively, you can declare resources as properties in a plain text file:\n\n``` text\n# en.txt\nhello_msg=Hi, {{user.name}}.\ngoodbye_msg=Bye, {{user.name}}.\n```\n\nThen load and parse the file:\n\n``` javascript\nvar resources = {};\n\n$.get(\"en.txt\", function (text) {\n    var lines = text.split(\"\\n\");\n    var i, key;\n\n    lines.forEach(function (line) {\n        if (line.length && line.charAt(0) !== \"#\") {\n            i = line.indexOf(\"=\");\n            key = line.substr(0, i).trim();\n            resources[key] = line.substr(i + 1).trim();\n        }\n    });\n\n}, \"html\");\n```\n\nIf you use Markup.js for markup and translation at the same time, you can\nassign your resource strings to the `includes` variable, then refer to these\nstrings from within your HTML templates:\n\n``` javascript\nMark.includes = {\n    hello_msg: \"Hi, {{user.name}}.\",\n    goodbye_msg: \"Bye, {{user.name}}.\"\n};\n\nvar template = \"<div class='hi-bye'>{{hello_msg}} {{goodbye_msg}}</div>\";\n\nvar context = {\n    user: { name: \"Adam\" }\n};\n\nvar result = Mark.up(template, context);\n// \"<div class='hi-bye'>Hi, Adam. Bye, Adam.</div>\"\n```\n\n### Pluralization\n\nThe `pluralize` pipe, provided in `src/extras/i18n.js`, handles pluralized\nforms in any language you require. To prepare your app for pluralization:\n\nFirst, add [pluralization functions](http://translate.sourceforge.net/wiki/l10n/pluralforms) \nto the `pluralize` pipe for the languages you intend to support (English is\nincluded by default). A pluralization function accepts an array of strings and\na number, then returns one of the strings:\n\n``` javascript\n...\nvar plurals = {\n    // English has two plural forms\n    \"en\": function (msgs, n) {\n        return msgs[n === 1 ? 0 : 1];\n    },\n    // Czech has three plural forms\n    \"cs\": function (msgs, n) {\n        return msgs[n === 1 ? 0 : (n >= 2 && n <= 4) ? 1 : 2];\n    }\n};\n...\n```\n\nNext, set the user's language, or detect it from the web browser:\n\n``` javascript\n...\nvar lang = navigator.language.split(\"-\")[0];\n\nif (!lang in plurals) {\n    lang = \"en\";\n}\n...\n```\n\nNext, create resource strings for the target language. For expressions that\nrequire pluralization, use \";;\" to delimit each plural form:\n\n``` javascript\n// English messages\nMark.includes = {\n    welcome_msg: \"Welcome, {{name}}. {{credit_msg|pluralize>`credits`}}\",\n    credit_msg: \"You have one credit.;;You have {{credits}} credits.\",\n    error_msg: \"Oops! There was an error.\"\n};\n```\n\nNotice how one include can include another, as `welcome_msg` includes\n`credit_msg`. Also notice how `pluralize` accepts a dynamic variable (in\nbackticks) to determine which part of `credit_msg` to extract.\n\nFinally, put it all together:\n\n``` javascript\nvar context = {\n    name: \"Adam\",\n    credits: 50\n};\n\nvar template = \"<p class='welcome'>{{welcome_msg}}</p>\";\n\nvar result = Mark.up(template, context);\n// \"<p class='welcome'>Welcome, Adam. You have 50 credits.</p>\"\n```\n\n### Dates, numbers and currencies\n\nWeb browsers provide no convenient way to format dates, although there are \nsome good libraries that you can drop into a custom pipe, like\n[Moment.js](http://momentjs.com/):\n\n``` javascript\nMark.pipes.moment = function (date, format) {\n    return moment(new Date(date)).format(format);\n};\n```\n\nOr you can simply use the browser's built-in locale methods:\n\n``` javascript\nMark.pipes.date = function (date) {\n    return new Date(+date || date).toLocaleDateString();\n};\n\nMark.pipes.time = function (date) {\n    return new Date(+date || date).toLocaleTimeString();\n};\n\nMark.pipes.datetime = function (date) {\n    return new Date(+date || date).toLocaleString();\n};\n```\n\nFor numbers and currencies, try \n[Accounting.js](http://josscrowcroft.github.com/accounting.js/):\n\n``` javascript\nMark.pipes.dollars = function (num) {\n    return accounting.formatMoney(+num);\n};\n\nMark.pipes.euros = function (num) {\n    return accounting.formatMoney(+num, \"€\", 2, \".\", \",\");\n};\n```\n\nSee `src/extras/dates.js` and `src/extras/numbers.js` for additional examples.\n\n## Compatibility\n\nMarkup.js is compatible with Chrome, Safari, Firefox, Internet Explorer 9,\nNode.js, and various mobile WebKit browsers. Please [submit an issue][2] to \nreport incompatibilities or other bugs. \n\n### Ports\n\nMarkup.js is also available for [PHP][3].\n\n## License\n\nCopyright (C) 2011 - 2013 by Adam Mark\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n[1]: #loop-counters\n[2]: https://github.com/adammark/Markup.js/issues\n[3]: https://github.com/mattparlane/Markup.php","maintainers":[{"name":"adammark","email":"adammark75@gmail.com"}],"time":{"modified":"2022-06-19T16:19:13.159Z","created":"2012-08-28T19:43:16.975Z","1.5.12":"2012-08-28T19:43:17.478Z","1.5.13":"2012-11-16T17:16:58.711Z","1.5.14":"2013-01-17T15:13:29.213Z","1.5.15":"2013-02-05T15:07:10.429Z","1.5.16":"2013-05-16T13:13:51.228Z","1.5.17":"2013-11-20T16:27:03.151Z","1.5.18":"2014-01-31T20:02:36.395Z","1.5.19":"2014-08-15T18:21:11.061Z","1.5.20":"2014-08-18T18:35:37.506Z","1.5.21":"2014-10-07T12:50:28.670Z"},"author":{"name":"Adam Mark"},"repository":{"type":"git","url":"https://github.com/adammark/Markup.js.git"},"readmeFilename":"README.md","homepage":"https://github.com/adammark/Markup.js","keywords":["markup","template","templating","html"],"bugs":{"url":"https://github.com/adammark/Markup.js/issues"},"users":{"ahvonenj":true}}