From c1c857bbadad0c483d94081033fcbf2316a02fdd Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 2 Dec 2016 14:38:39 +0700 Subject: [PATCH 01/48] Ethereum => Link --- src/views/index.jade | 2 +- src/views/layout.jade | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/index.jade b/src/views/index.jade index 6b14bb2..cad03a5 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -163,7 +163,7 @@ block content div.active-nodes.text-warning i.icon-warning-o span.small-title ATTENTION! - span.small-value This page does not represent the entire state of the ethereum network - listing a node on this page is a voluntary process. + span.small-value This page does not represent the entire state of the Link network - listing a node on this page is a voluntary process. //- div.col-xs-12.stat-holder.box //- div.active-nodes.text-danger //- i.icon-hashrate diff --git a/src/views/layout.jade b/src/views/layout.jade index 4822caa..216ff88 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -3,11 +3,11 @@ doctype html html(ng-app="netStatsApp") head meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0") - title Ethereum Network Status + title Link Network Status style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') body block content - script(src="/js/netstats.min.js") \ No newline at end of file + script(src="/js/netstats.min.js") From aad7a3e89576f9a530b372c0c98f3eaa7370d6ad Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 2 Dec 2016 14:39:46 +0700 Subject: [PATCH 02/48] Remove Google Analytics. --- src/js/script.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/js/script.js b/src/js/script.js index 1881020..469b20f 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -26,12 +26,3 @@ moment.relativeTimeThreshold('M', 12); })(); - -(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ -(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), -m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) -})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - -// ga('create', 'UA-68390837-2', 'auto'); -ga('create', 'UA-80834434-1', 'auto'); -ga('send', 'pageview'); \ No newline at end of file From 9ef5ae4cdbdc3ac7c9eaaceab64c42b05eb6f47d Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 2 Dec 2016 14:46:29 +0700 Subject: [PATCH 03/48] Status => Stats --- src/views/layout.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/layout.jade b/src/views/layout.jade index 216ff88..5c9d164 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -3,7 +3,7 @@ doctype html html(ng-app="netStatsApp") head meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0") - title Link Network Status + title Link Network Stats style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') From c59c499062ddf15598da19327132534304a526b0 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sat, 2 Sep 2017 17:38:55 +0700 Subject: [PATCH 04/48] Link => LINK --- src/views/index.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/index.jade b/src/views/index.jade index cad03a5..8602873 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -163,7 +163,7 @@ block content div.active-nodes.text-warning i.icon-warning-o span.small-title ATTENTION! - span.small-value This page does not represent the entire state of the Link network - listing a node on this page is a voluntary process. + span.small-value This page does not represent the entire state of the LINK network - listing a node on this page is a voluntary process. //- div.col-xs-12.stat-holder.box //- div.active-nodes.text-danger //- i.icon-hashrate From 50e37827b1737621cb64ab28c2ba070188f3d0e2 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sat, 2 Sep 2017 17:47:47 +0700 Subject: [PATCH 05/48] Add favicon. --- src/images/link-logo.svg | 1 + src/views/layout.jade | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/images/link-logo.svg diff --git a/src/images/link-logo.svg b/src/images/link-logo.svg new file mode 100644 index 0000000..3ce7a3b --- /dev/null +++ b/src/images/link-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/views/layout.jade b/src/views/layout.jade index 5c9d164..4db7ba9 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -3,10 +3,11 @@ doctype html html(ng-app="netStatsApp") head meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0") - title Link Network Stats + title LINK Network Stats style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } - link(rel='stylesheet', href='//fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') + link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') + link(rel='shortcut icon', href='images/link-logo.svg', type='image/x-icon') body block content From ef69431bf737a178a9fc7caad71369292b46f6bb Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sat, 2 Sep 2017 17:58:50 +0700 Subject: [PATCH 06/48] Fix favicon. --- src/views/layout.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/layout.jade b/src/views/layout.jade index 4db7ba9..9e185a9 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -7,7 +7,7 @@ html(ng-app="netStatsApp") style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') - link(rel='shortcut icon', href='images/link-logo.svg', type='image/x-icon') + link(rel='shortcut icon', href='https://www.link-blockchain.org/images/link-logo.svg', type='image/x-icon') body block content From ef93dd6cd99e51c67dac05c76f98d8f9c5cb05de Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Mon, 4 Sep 2017 11:38:22 +0700 Subject: [PATCH 07/48] Use local favicon. --- Gruntfile.js | 2 +- package-lock.json | 2061 +++++++++++++++++++++++++++++++++++++++++ src/views/layout.jade | 2 +- 3 files changed, 2063 insertions(+), 2 deletions(-) create mode 100644 package-lock.json diff --git a/Gruntfile.js b/Gruntfile.js index 50e4099..6ebc04e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -113,7 +113,7 @@ module.exports = function(grunt) { { expand: true, cwd: 'src/images/', - src: ['*.ico'], + src: ['*.*'], dest: 'dist/', filter: 'isFile' }, diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..804f4da --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2061 @@ +{ + "name": "eth-netstats", + "version": "0.0.9", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + }, + "accepts": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", + "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.5.3" + } + }, + "access-control": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/access-control/-/access-control-1.0.0.tgz", + "integrity": "sha1-rrooLO53MT6FJAFj1p41sp421iY=", + "requires": { + "millisecond": "0.1.2", + "setheader": "0.0.4", + "vary": "1.1.1" + }, + "dependencies": { + "vary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" + } + } + }, + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + }, + "acorn-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "requires": { + "acorn": "2.7.0" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "requires": { + "underscore": "1.7.0", + "underscore.string": "2.4.0" + }, + "dependencies": { + "underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=" + } + } + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" + }, + "async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" + }, + "asyncemit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/asyncemit/-/asyncemit-3.0.1.tgz", + "integrity": "sha1-zD4P4No5tTzBXls6qGFupqcr1Zk=" + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "requires": { + "buffers": "0.1.1", + "chainsaw": "0.1.0" + } + }, + "body-parser": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", + "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", + "requires": { + "bytes": "2.1.0", + "content-type": "1.0.2", + "debug": "2.2.0", + "depd": "1.0.1", + "http-errors": "1.3.1", + "iconv-lite": "0.4.11", + "on-finished": "2.3.0", + "qs": "4.0.0", + "raw-body": "2.1.7", + "type-is": "1.6.15" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "requires": { + "pako": "0.2.9" + } + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", + "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=" + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "requires": { + "traverse": "0.3.9" + } + }, + "chalk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", + "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "character-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=" + }, + "clean-css": { + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", + "requires": { + "commander": "2.8.1", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + } + } + }, + "coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=" + }, + "color": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/color/-/color-0.8.0.tgz", + "integrity": "sha1-iQwHw/1OZJU3Y4kRz2keVFi2/KU=", + "requires": { + "color-convert": "0.5.3", + "color-string": "0.3.0" + } + }, + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "requires": { + "color-name": "1.1.3" + } + }, + "colornames": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-0.0.2.tgz", + "integrity": "sha1-2BH9bIT1kClJmorEQ2ICk1uSvjE=" + }, + "colors": { + "version": "0.6.0-1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.0-1.tgz", + "integrity": "sha1-bbtozri8YPKzE9zFzhWZ8G0Z5no=" + }, + "colorspace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.0.1.tgz", + "integrity": "sha1-yZx5btMRKLmHalLh7l7gOkpxl0k=", + "requires": { + "color": "0.8.0", + "text-hex": "0.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "connected": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/connected/-/connected-0.0.2.tgz", + "integrity": "sha1-e1dVshbOMf+rzMOOn04d/Bw7fG0=" + }, + "constantinople": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=", + "requires": { + "acorn": "2.7.0" + } + }, + "content-disposition": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", + "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=" + }, + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "cookie": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-server": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/create-server/-/create-server-1.0.1.tgz", + "integrity": "sha1-FkNCg08Yi77Hx7xGZ0Y8wrEwTEQ=", + "requires": { + "connected": "0.0.2" + } + }, + "css": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=", + "requires": { + "css-parse": "1.0.4", + "css-stringify": "1.0.5" + } + }, + "css-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=" + }, + "css-stringify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=" + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "1.0.2" + } + }, + "d3": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.6.tgz", + "integrity": "sha1-lFHGUcpzP7lnLIH7fyZVFkpzpC0=" + }, + "dateformat": { + "version": "1.0.2-1.2.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", + "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "depd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" + }, + "destroy": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", + "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" + }, + "diagnostics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.0.tgz", + "integrity": "sha1-4QkJALSVI+hSe+IPCBJ1IF8q42o=", + "requires": { + "colorspace": "1.0.1", + "enabled": "1.0.2", + "kuler": "0.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz", + "integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=" + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.3" + } + }, + "env-variable": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.3.tgz", + "integrity": "sha1-uGwWQb5WECZ9UG8YBx6nbXBwl8s=" + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-html": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz", + "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "etag": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=" + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "express": { + "version": "4.13.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz", + "integrity": "sha1-3bLx+0UCvzNZjSsDKwN5YMpsgKM=", + "requires": { + "accepts": "1.2.13", + "array-flatten": "1.1.1", + "content-disposition": "0.5.0", + "content-type": "1.0.2", + "cookie": "0.1.3", + "cookie-signature": "1.0.6", + "debug": "2.2.0", + "depd": "1.0.1", + "escape-html": "1.0.2", + "etag": "1.7.0", + "finalhandler": "0.4.0", + "fresh": "0.3.0", + "merge-descriptors": "1.0.0", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.1", + "path-to-regexp": "0.1.7", + "proxy-addr": "1.0.10", + "qs": "4.0.0", + "range-parser": "1.0.3", + "send": "0.13.0", + "serve-static": "1.10.3", + "type-is": "1.6.15", + "utils-merge": "1.0.0", + "vary": "1.0.1" + } + }, + "extendible": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/extendible/-/extendible-0.1.1.tgz", + "integrity": "sha1-4qN+2HEp+0+VM+io11BiMKU5yQU=" + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=" + }, + "finalhandler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", + "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", + "requires": { + "debug": "2.2.0", + "escape-html": "1.0.2", + "on-finished": "2.3.0", + "unpipe": "1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findup-sync": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", + "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "requires": { + "glob": "3.2.11", + "lodash": "2.4.2" + }, + "dependencies": { + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + } + } + }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "forwarded-for": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/forwarded-for/-/forwarded-for-1.0.1.tgz", + "integrity": "sha1-59pIFAJRaP/AoQ0/954UFfRq9Gk=" + }, + "fresh": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=" + }, + "fstream": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz", + "integrity": "sha1-czfwWPu7vvqMn1YaKMqwhJICyYg=", + "requires": { + "graceful-fs": "3.0.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.0.3" + }, + "dependencies": { + "graceful-fs": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", + "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", + "requires": { + "natives": "1.1.0" + } + } + } + }, + "fusing": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fusing/-/fusing-1.0.0.tgz", + "integrity": "sha1-VQwV12r5Jld4qgUezkTUAAoJjUU=", + "requires": { + "emits": "3.0.0", + "predefine": "0.1.2" + } + }, + "geoip-lite": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/geoip-lite/-/geoip-lite-1.1.6.tgz", + "integrity": "sha1-aAH3QMJ/ONRuGFrIMj35yDFehOc=", + "requires": { + "async": "0.1.22", + "colors": "0.6.0-1", + "glob": "3.2.11", + "iconv-lite": "0.4.11", + "lazy": "1.0.11", + "rimraf": "2.0.3", + "unzip": "0.0.4" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=" + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + } + }, + "graceful-fs": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz", + "integrity": "sha1-BweNtfY3f2Mh/Oqu30l94STclGU=", + "optional": true + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "grunt": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", + "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "requires": { + "async": "0.1.22", + "coffee-script": "1.3.3", + "colors": "0.6.2", + "dateformat": "1.0.2-1.2.3", + "eventemitter2": "0.4.14", + "exit": "0.1.2", + "findup-sync": "0.1.3", + "getobject": "0.1.0", + "glob": "3.1.21", + "grunt-legacy-log": "0.1.3", + "grunt-legacy-util": "0.2.0", + "hooker": "0.2.3", + "iconv-lite": "0.2.11", + "js-yaml": "2.0.5", + "lodash": "0.9.2", + "minimatch": "0.2.14", + "nopt": "1.0.10", + "rimraf": "2.2.8", + "underscore.string": "2.2.1", + "which": "1.0.9" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "requires": { + "graceful-fs": "1.2.3", + "inherits": "1.0.2", + "minimatch": "0.2.14" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=" + }, + "iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=" + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=" + }, + "lodash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=" + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + } + } + }, + "grunt-contrib-clean": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", + "integrity": "sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY=", + "requires": { + "rimraf": "2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + } + } + }, + "grunt-contrib-concat": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz", + "integrity": "sha1-lTxu/f39LBB6uchQd/LUsk0xzUk=", + "requires": { + "chalk": "0.5.1", + "source-map": "0.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" + }, + "chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "requires": { + "ansi-styles": "1.1.0", + "escape-string-regexp": "1.0.5", + "has-ansi": "0.1.0", + "strip-ansi": "0.3.0", + "supports-color": "0.2.0" + } + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "requires": { + "ansi-regex": "0.2.1" + } + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "requires": { + "ansi-regex": "0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" + } + } + }, + "grunt-contrib-copy": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.8.2.tgz", + "integrity": "sha1-3zHJD/zECbyfr+ROwN0eQlmRb+o=", + "requires": { + "chalk": "1.1.1", + "file-sync-cmp": "0.1.1" + } + }, + "grunt-contrib-cssmin": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-0.12.3.tgz", + "integrity": "sha1-QVdZYJb7dlb8RktMx7B0beHzkBQ=", + "requires": { + "chalk": "1.1.1", + "clean-css": "3.4.28", + "maxmin": "1.1.0" + } + }, + "grunt-contrib-jade": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-0.14.1.tgz", + "integrity": "sha1-5nkmZdsC2kFti6ZmhAGjihaxYl0=", + "requires": { + "chalk": "0.5.1", + "jade": "1.9.2" + }, + "dependencies": { + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" + }, + "chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "requires": { + "ansi-styles": "1.1.0", + "escape-string-regexp": "1.0.5", + "has-ansi": "0.1.0", + "strip-ansi": "0.3.0", + "supports-color": "0.2.0" + } + }, + "commander": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "requires": { + "ansi-regex": "0.2.1" + } + }, + "jade": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.9.2.tgz", + "integrity": "sha1-C4n5xg1OrSc46Ca6eyzKyaVwKr4=", + "requires": { + "character-parser": "1.2.1", + "commander": "2.6.0", + "constantinople": "3.0.2", + "mkdirp": "0.5.1", + "transformers": "2.1.0", + "void-elements": "2.0.1", + "with": "4.0.3" + } + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "requires": { + "ansi-regex": "0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" + } + } + }, + "grunt-contrib-uglify": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.9.2.tgz", + "integrity": "sha1-GmHG8hJBDkq7T3yJFTcXsQFWAmA=", + "requires": { + "chalk": "1.1.1", + "lodash": "3.10.1", + "maxmin": "1.1.0", + "uglify-js": "2.8.29", + "uri-path": "0.0.2" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + } + } + } + }, + "grunt-legacy-log": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", + "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "requires": { + "colors": "0.6.2", + "grunt-legacy-log-utils": "0.1.1", + "hooker": "0.2.3", + "lodash": "2.4.2", + "underscore.string": "2.3.3" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=" + } + } + }, + "grunt-legacy-log-utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", + "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "requires": { + "colors": "0.6.2", + "lodash": "2.4.2", + "underscore.string": "2.3.3" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=" + } + } + }, + "grunt-legacy-util": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", + "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "requires": { + "async": "0.1.22", + "exit": "0.1.2", + "getobject": "0.1.0", + "hooker": "0.2.3", + "lodash": "0.9.2", + "underscore.string": "2.2.1", + "which": "1.0.9" + }, + "dependencies": { + "lodash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=" + } + } + }, + "gzip-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", + "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", + "requires": { + "browserify-zlib": "0.1.4", + "concat-stream": "1.6.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=" + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" + }, + "http-errors": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", + "requires": { + "inherits": "2.0.3", + "statuses": "1.3.1" + } + }, + "iconv-lite": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", + "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "2.0.1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", + "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jade": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=", + "requires": { + "character-parser": "1.2.1", + "clean-css": "3.4.28", + "commander": "2.6.0", + "constantinople": "3.0.2", + "jstransformer": "0.0.2", + "mkdirp": "0.5.1", + "transformers": "2.1.0", + "uglify-js": "2.8.29", + "void-elements": "2.0.1", + "with": "4.0.3" + }, + "dependencies": { + "commander": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + } + } + } + }, + "js-yaml": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", + "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "requires": { + "argparse": "0.1.16", + "esprima": "1.0.4" + } + }, + "jstransformer": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=", + "requires": { + "is-promise": "2.1.0", + "promise": "6.1.0" + }, + "dependencies": { + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "promise": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=", + "requires": { + "asap": "1.0.0" + } + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + }, + "kuler": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-0.0.0.tgz", + "integrity": "sha1-tmu0a5NOVQ9Z2BiEjgq7pPf1VTw=", + "requires": { + "colornames": "0.0.2" + } + }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + } + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "maxmin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "requires": { + "chalk": "1.1.1", + "figures": "1.7.0", + "gzip-size": "1.0.0", + "pretty-bytes": "1.0.4" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "merge-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz", + "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "millisecond": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz", + "integrity": "sha1-bMWtOGJByrjniv+WT4cCjuyS2sU=" + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "natives": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", + "integrity": "sha1-6f+EFBimsux6SV6TmYT3jxY+bjE=" + }, + "negotiator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", + "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=" + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1.1.0" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "requires": { + "wordwrap": "0.0.3" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "over": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/over/-/over-0.0.5.tgz", + "integrity": "sha1-8phS5w/X4l82DgE6jsRMgq7bVwg=" + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.1" + } + }, + "parseurl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "predefine": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/predefine/-/predefine-0.1.2.tgz", + "integrity": "sha1-KqkrRJa8H4VU5DpF92v75Q0z038=", + "requires": { + "extendible": "0.1.1" + } + }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "requires": { + "get-stdin": "4.0.1", + "meow": "3.7.0" + } + }, + "primus": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/primus/-/primus-6.1.0.tgz", + "integrity": "sha1-s79Mk46weHS4crwrDOnA2oVdbBI=", + "requires": { + "access-control": "1.0.0", + "asyncemit": "3.0.1", + "create-server": "1.0.1", + "diagnostics": "1.1.0", + "eventemitter3": "2.0.3", + "forwarded-for": "1.0.1", + "fusing": "1.0.0", + "setheader": "0.0.4", + "ultron": "1.1.0", + "yeast": "0.1.2" + } + }, + "primus-emit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/primus-emit/-/primus-emit-1.0.0.tgz", + "integrity": "sha1-5LIxaHBsvqfLpjC0goBtv/30w+k=" + }, + "primus-spark-latency": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/primus-spark-latency/-/primus-spark-latency-0.1.1.tgz", + "integrity": "sha1-Mo04R2esLUriKvBr3SWwx4U9KZE=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=", + "requires": { + "is-promise": "1.0.1" + } + }, + "proxy-addr": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", + "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", + "requires": { + "forwarded": "0.1.0", + "ipaddr.js": "1.0.5" + } + }, + "pullstream": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/pullstream/-/pullstream-0.0.4.tgz", + "integrity": "sha1-Qdg8RG0pDi8uubaB0/O1b+6IoK8=", + "requires": { + "over": "0.0.5", + "stream-buffers": "0.2.6" + } + }, + "qs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", + "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" + }, + "range-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", + "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" + }, + "raw-body": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "requires": { + "bytes": "2.4.0", + "iconv-lite": "0.4.13", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "1.0.2" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.0.3.tgz", + "integrity": "sha1-9QopZecUTpr9mYmC8V33BnMPVqk=", + "requires": { + "graceful-fs": "1.1.14" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + }, + "send": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz", + "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=", + "requires": { + "debug": "2.2.0", + "depd": "1.0.1", + "destroy": "1.0.3", + "escape-html": "1.0.2", + "etag": "1.7.0", + "fresh": "0.3.0", + "http-errors": "1.3.1", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "2.3.0", + "range-parser": "1.0.3", + "statuses": "1.2.1" + }, + "dependencies": { + "statuses": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", + "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" + } + } + }, + "serve-static": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", + "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", + "requires": { + "escape-html": "1.0.3", + "parseurl": "1.3.1", + "send": "0.13.2" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "send": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", + "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", + "requires": { + "debug": "2.2.0", + "depd": "1.1.1", + "destroy": "1.0.4", + "escape-html": "1.0.3", + "etag": "1.7.0", + "fresh": "0.3.0", + "http-errors": "1.3.1", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "2.3.0", + "range-parser": "1.0.3", + "statuses": "1.2.1" + } + }, + "statuses": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", + "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" + } + } + }, + "setheader": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/setheader/-/setheader-0.0.4.tgz", + "integrity": "sha1-km7SjPdiFJYgkx566j8blYFuxpQ=", + "requires": { + "debug": "0.7.4" + }, + "dependencies": { + "debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + } + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", + "integrity": "sha1-hYb7mloAXltQHiHNGLbyG0V60fk=", + "requires": { + "amdefine": "1.0.1" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "stream-buffers": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-0.2.6.tgz", + "integrity": "sha1-GBwI1bs2kARfaUAbmuanoM8zE/w=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "text-hex": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-0.0.0.tgz", + "integrity": "sha1-V4+8haapJjbkLdF7QdAhjM6esrM=" + }, + "transformers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", + "requires": { + "css": "1.0.8", + "promise": "2.0.0", + "uglify-js": "2.2.5" + } + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=", + "requires": { + "optimist": "0.3.7", + "source-map": "0.1.43" + }, + "dependencies": { + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "ultron": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", + "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + }, + "underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unzip": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/unzip/-/unzip-0.0.4.tgz", + "integrity": "sha1-/2fKhClbZRYdXH8vNAmJx43GCVo=", + "requires": { + "binary": "0.3.0", + "fstream": "0.1.31", + "pullstream": "0.0.4" + } + }, + "uri-path": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-0.0.2.tgz", + "integrity": "sha1-gD6wHy/rF5J9zOD2GH5yt19T9VQ=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "vary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", + "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=" + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, + "which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=" + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "with": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", + "requires": { + "acorn": "1.2.2", + "acorn-globals": "1.0.9" + }, + "dependencies": { + "acorn": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=" + } + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "ws": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", + "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + }, + "dependencies": { + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + } + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/src/views/layout.jade b/src/views/layout.jade index 9e185a9..36a519b 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -7,7 +7,7 @@ html(ng-app="netStatsApp") style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') - link(rel='shortcut icon', href='https://www.link-blockchain.org/images/link-logo.svg', type='image/x-icon') + link(rel='shortcut icon', href='/link-logo.svg', type='image/x-icon') body block content From 44a2d68e1c3511a020b4c64159ab4da4f55fdbb3 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Mon, 4 Sep 2017 11:47:43 +0700 Subject: [PATCH 08/48] Remove Ethereum favicons. --- src-lite/images/favicon.ico | Bin 574 -> 0 bytes src-lite/images/favicon.png | Bin 574 -> 0 bytes src/images/favicon.ico | Bin 574 -> 0 bytes src/images/favicon.png | Bin 574 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src-lite/images/favicon.ico delete mode 100644 src-lite/images/favicon.png delete mode 100644 src/images/favicon.ico delete mode 100644 src/images/favicon.png diff --git a/src-lite/images/favicon.ico b/src-lite/images/favicon.ico deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| diff --git a/src-lite/images/favicon.png b/src-lite/images/favicon.png deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| diff --git a/src/images/favicon.ico b/src/images/favicon.ico deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| diff --git a/src/images/favicon.png b/src/images/favicon.png deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| From 86b0595435b0a34e9b4dfd0093bf61fb819e29f5 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sat, 7 Oct 2017 17:09:41 +0700 Subject: [PATCH 09/48] LINK => MIX --- src/views/index.jade | 2 +- src/views/layout.jade | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/index.jade b/src/views/index.jade index 8602873..ec4f052 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -163,7 +163,7 @@ block content div.active-nodes.text-warning i.icon-warning-o span.small-title ATTENTION! - span.small-value This page does not represent the entire state of the LINK network - listing a node on this page is a voluntary process. + span.small-value This page does not represent the entire state of the MIX network - listing a node on this page is a voluntary process. //- div.col-xs-12.stat-holder.box //- div.active-nodes.text-danger //- i.icon-hashrate diff --git a/src/views/layout.jade b/src/views/layout.jade index 36a519b..3797b78 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -3,7 +3,7 @@ doctype html html(ng-app="netStatsApp") head meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0") - title LINK Network Stats + title MIX Network Stats style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') From 2999d4a65d763f54a8aa32668c4d05bf7f450c0c Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Tue, 28 Nov 2017 12:45:05 +0700 Subject: [PATCH 10/48] Update favicon. --- src/images/mix-logo-thick.svg | 55 +++++++++++++++++++++++++++++++++++ src/views/layout.jade | 2 +- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/images/mix-logo-thick.svg diff --git a/src/images/mix-logo-thick.svg b/src/images/mix-logo-thick.svg new file mode 100644 index 0000000..ddf1c66 --- /dev/null +++ b/src/images/mix-logo-thick.svg @@ -0,0 +1,55 @@ + +image/svg+xml diff --git a/src/views/layout.jade b/src/views/layout.jade index 3797b78..8f1f835 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -7,7 +7,7 @@ html(ng-app="netStatsApp") style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') - link(rel='shortcut icon', href='/link-logo.svg', type='image/x-icon') + link(rel='shortcut icon', href='/mix-logo-thick.svg', type='image/x-icon') body block content From 65827c30361ea4acf193940da97504bfcdcd2f15 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Thu, 3 May 2018 15:30:13 +0700 Subject: [PATCH 11/48] Include more favicon sizes. --- src/images/mix-logo-thick-1024.png | Bin 0 -> 94536 bytes src/images/mix-logo-thick-128.png | Bin 0 -> 7584 bytes src/images/mix-logo-thick-256.png | Bin 0 -> 17256 bytes src/images/mix-logo-thick-512.png | Bin 0 -> 40144 bytes src/images/mix-logo-thick-64.png | Bin 0 -> 3410 bytes src/views/layout.jade | 7 ++++++- 6 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/images/mix-logo-thick-1024.png create mode 100644 src/images/mix-logo-thick-128.png create mode 100644 src/images/mix-logo-thick-256.png create mode 100644 src/images/mix-logo-thick-512.png create mode 100644 src/images/mix-logo-thick-64.png diff --git a/src/images/mix-logo-thick-1024.png b/src/images/mix-logo-thick-1024.png new file mode 100644 index 0000000000000000000000000000000000000000..7fc6e559a2fac98a2867d986de92fd19614cb3b7 GIT binary patch literal 94536 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�vybi18j9 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 D*~5J^ literal 0 HcmV?d00001 diff --git a/src/images/mix-logo-thick-512.png b/src/images/mix-logo-thick-512.png new file mode 100644 index 0000000000000000000000000000000000000000..7df8f98e050290bab0291086075fe1124d795579 GIT binary patch literal 40144 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 Qi~?MGT1J{x>Q2c20li#3=>Px# literal 0 HcmV?d00001 diff --git a/src/images/mix-logo-thick-64.png b/src/images/mix-logo-thick-64.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b0fe4e4500531dcceffd623071b0faeb5f904f GIT binary patch literal 3410 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 literal 0 HcmV?d00001 diff --git a/src/views/layout.jade b/src/views/layout.jade index 8f1f835..6750f97 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -7,7 +7,12 @@ html(ng-app="netStatsApp") style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') - link(rel='shortcut icon', href='/mix-logo-thick.svg', type='image/x-icon') + link(rel='shortcut icon', href='/mix-logo-thick.svg', sizes='any' type='image/svg+xml') + link(rel='shortcut icon', href='/mix-logo-thick-1024.png', sizes='1024x1024' type='image/png') + link(rel='shortcut icon', href='/mix-logo-thick-512.png', sizes='512x512' type='image/png') + link(rel='shortcut icon', href='/mix-logo-thick-256.png', sizes='256x256' type='image/png') + link(rel='shortcut icon', href='/mix-logo-thick-128.png', sizes='128x128' type='image/png') + link(rel='shortcut icon', href='/mix-logo-thick-64.png', sizes='64x64' type='image/png') body block content From fa365e40e53f896105204d20959043f4c559e406 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Thu, 3 May 2018 15:56:43 +0700 Subject: [PATCH 12/48] Fix it for China. --- Gruntfile.js | 2 +- package-lock.json | 602 +++++++++++------------ src/css/style.css | 37 +- src/fonts/SourceSansPro-Bold.woff2 | Bin 0 -> 15480 bytes src/fonts/SourceSansPro-ExtraLight.woff2 | Bin 0 -> 15472 bytes src/fonts/SourceSansPro-Light.woff2 | Bin 0 -> 15764 bytes src/fonts/SourceSansPro-Regular.woff2 | Bin 0 -> 15908 bytes src/fonts/SourceSansPro-SemiBold.woff2 | Bin 0 -> 15784 bytes src/views/layout.jade | 1 - 9 files changed, 338 insertions(+), 304 deletions(-) create mode 100644 src/fonts/SourceSansPro-Bold.woff2 create mode 100644 src/fonts/SourceSansPro-ExtraLight.woff2 create mode 100644 src/fonts/SourceSansPro-Light.woff2 create mode 100644 src/fonts/SourceSansPro-Regular.woff2 create mode 100644 src/fonts/SourceSansPro-SemiBold.woff2 diff --git a/Gruntfile.js b/Gruntfile.js index 6ebc04e..4fd409d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -106,7 +106,7 @@ module.exports = function(grunt) { { expand: true, cwd: 'src/fonts/', - src: ['minimal-*.*'], + src: ['*.*'], dest: 'dist/fonts/', filter: 'isFile' }, diff --git a/package-lock.json b/package-lock.json index 804f4da..762ea8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", "requires": { - "mime-types": "2.1.17", + "mime-types": "~2.1.6", "negotiator": "0.5.3" } }, @@ -23,9 +23,9 @@ "resolved": "https://registry.npmjs.org/access-control/-/access-control-1.0.0.tgz", "integrity": "sha1-rrooLO53MT6FJAFj1p41sp421iY=", "requires": { - "millisecond": "0.1.2", - "setheader": "0.0.4", - "vary": "1.1.1" + "millisecond": "0.1.x", + "setheader": "0.0.x", + "vary": "1.1.x" }, "dependencies": { "vary": { @@ -45,7 +45,7 @@ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", "requires": { - "acorn": "2.7.0" + "acorn": "^2.1.0" } }, "align-text": { @@ -53,9 +53,9 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -78,8 +78,8 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", "requires": { - "underscore": "1.7.0", - "underscore.string": "2.4.0" + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" }, "dependencies": { "underscore.string": { @@ -119,8 +119,8 @@ "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", "requires": { - "buffers": "0.1.1", - "chainsaw": "0.1.0" + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" } }, "body-parser": { @@ -129,15 +129,15 @@ "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", "requires": { "bytes": "2.1.0", - "content-type": "1.0.2", - "debug": "2.2.0", - "depd": "1.0.1", - "http-errors": "1.3.1", + "content-type": "~1.0.1", + "debug": "~2.2.0", + "depd": "~1.0.1", + "http-errors": "~1.3.1", "iconv-lite": "0.4.11", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "4.0.0", - "raw-body": "2.1.7", - "type-is": "1.6.15" + "raw-body": "~2.1.2", + "type-is": "~1.6.6" } }, "browserify-zlib": { @@ -145,7 +145,7 @@ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", "requires": { - "pako": "0.2.9" + "pako": "~0.2.0" } }, "buffers": { @@ -173,8 +173,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } }, "center-align": { @@ -182,8 +182,8 @@ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chainsaw": { @@ -191,7 +191,7 @@ "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", "requires": { - "traverse": "0.3.9" + "traverse": ">=0.3.0 <0.4" } }, "chalk": { @@ -199,11 +199,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.1.0", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "character-parser": { @@ -216,8 +216,8 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", "requires": { - "commander": "2.8.1", - "source-map": "0.4.4" + "commander": "2.8.x", + "source-map": "0.4.x" }, "dependencies": { "source-map": { @@ -225,7 +225,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -235,8 +235,8 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -257,8 +257,8 @@ "resolved": "https://registry.npmjs.org/color/-/color-0.8.0.tgz", "integrity": "sha1-iQwHw/1OZJU3Y4kRz2keVFi2/KU=", "requires": { - "color-convert": "0.5.3", - "color-string": "0.3.0" + "color-convert": "^0.5.0", + "color-string": "^0.3.0" } }, "color-convert": { @@ -276,7 +276,7 @@ "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", "requires": { - "color-name": "1.1.3" + "color-name": "^1.0.0" } }, "colornames": { @@ -294,8 +294,8 @@ "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.0.1.tgz", "integrity": "sha1-yZx5btMRKLmHalLh7l7gOkpxl0k=", "requires": { - "color": "0.8.0", - "text-hex": "0.0.0" + "color": "0.8.x", + "text-hex": "0.0.x" } }, "commander": { @@ -303,7 +303,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "concat-stream": { @@ -311,9 +311,9 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "connected": { @@ -326,7 +326,7 @@ "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=", "requires": { - "acorn": "2.7.0" + "acorn": "^2.1.0" } }, "content-disposition": { @@ -359,7 +359,7 @@ "resolved": "https://registry.npmjs.org/create-server/-/create-server-1.0.1.tgz", "integrity": "sha1-FkNCg08Yi77Hx7xGZ0Y8wrEwTEQ=", "requires": { - "connected": "0.0.2" + "connected": "0.0.x" } }, "css": { @@ -386,7 +386,7 @@ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "requires": { - "array-find-index": "1.0.2" + "array-find-index": "^1.0.1" } }, "d3": { @@ -427,9 +427,9 @@ "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.0.tgz", "integrity": "sha1-4QkJALSVI+hSe+IPCBJ1IF8q42o=", "requires": { - "colorspace": "1.0.1", - "enabled": "1.0.2", - "kuler": "0.0.0" + "colorspace": "1.0.x", + "enabled": "1.0.x", + "kuler": "0.0.x" } }, "ee-first": { @@ -447,7 +447,7 @@ "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "requires": { - "env-variable": "0.0.3" + "env-variable": "0.0.x" } }, "env-variable": { @@ -460,7 +460,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "escape-html": { @@ -503,31 +503,31 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz", "integrity": "sha1-3bLx+0UCvzNZjSsDKwN5YMpsgKM=", "requires": { - "accepts": "1.2.13", + "accepts": "~1.2.12", "array-flatten": "1.1.1", "content-disposition": "0.5.0", - "content-type": "1.0.2", + "content-type": "~1.0.1", "cookie": "0.1.3", "cookie-signature": "1.0.6", - "debug": "2.2.0", - "depd": "1.0.1", + "debug": "~2.2.0", + "depd": "~1.0.1", "escape-html": "1.0.2", - "etag": "1.7.0", + "etag": "~1.7.0", "finalhandler": "0.4.0", "fresh": "0.3.0", "merge-descriptors": "1.0.0", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.1", + "methods": "~1.1.1", + "on-finished": "~2.3.0", + "parseurl": "~1.3.0", "path-to-regexp": "0.1.7", - "proxy-addr": "1.0.10", + "proxy-addr": "~1.0.8", "qs": "4.0.0", - "range-parser": "1.0.3", + "range-parser": "~1.0.2", "send": "0.13.0", - "serve-static": "1.10.3", - "type-is": "1.6.15", + "serve-static": "~1.10.0", + "type-is": "~1.6.6", "utils-merge": "1.0.0", - "vary": "1.0.1" + "vary": "~1.0.1" } }, "extendible": { @@ -540,8 +540,8 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" } }, "file-sync-cmp": { @@ -554,10 +554,10 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", "requires": { - "debug": "2.2.0", + "debug": "~2.2.0", "escape-html": "1.0.2", - "on-finished": "2.3.0", - "unpipe": "1.0.0" + "on-finished": "~2.3.0", + "unpipe": "~1.0.0" } }, "find-up": { @@ -565,8 +565,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { @@ -574,8 +574,8 @@ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", "requires": { - "glob": "3.2.11", - "lodash": "2.4.2" + "glob": "~3.2.9", + "lodash": "~2.4.1" }, "dependencies": { "lodash": { @@ -605,10 +605,10 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-0.1.31.tgz", "integrity": "sha1-czfwWPu7vvqMn1YaKMqwhJICyYg=", "requires": { - "graceful-fs": "3.0.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.0.3" + "graceful-fs": "~3.0.2", + "inherits": "~2.0.0", + "mkdirp": "0.5", + "rimraf": "2" }, "dependencies": { "graceful-fs": { @@ -616,7 +616,7 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", "requires": { - "natives": "1.1.0" + "natives": "^1.1.0" } } } @@ -626,8 +626,8 @@ "resolved": "https://registry.npmjs.org/fusing/-/fusing-1.0.0.tgz", "integrity": "sha1-VQwV12r5Jld4qgUezkTUAAoJjUU=", "requires": { - "emits": "3.0.0", - "predefine": "0.1.2" + "emits": "3.0.x", + "predefine": "0.1.x" } }, "geoip-lite": { @@ -635,13 +635,13 @@ "resolved": "https://registry.npmjs.org/geoip-lite/-/geoip-lite-1.1.6.tgz", "integrity": "sha1-aAH3QMJ/ONRuGFrIMj35yDFehOc=", "requires": { - "async": "0.1.22", + "async": "~0.1.22", "colors": "0.6.0-1", - "glob": "3.2.11", - "iconv-lite": "0.4.11", - "lazy": "1.0.11", - "rimraf": "2.0.3", - "unzip": "0.0.4" + "glob": "~3.2.1", + "iconv-lite": "~0.4.7", + "lazy": "~1.0.11", + "rimraf": "~2.0.2", + "unzip": "~0.0.4" } }, "get-stdin": { @@ -659,8 +659,8 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", "requires": { - "inherits": "2.0.3", - "minimatch": "0.3.0" + "inherits": "2", + "minimatch": "0.3" } }, "graceful-fs": { @@ -679,26 +679,26 @@ "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", "requires": { - "async": "0.1.22", - "coffee-script": "1.3.3", - "colors": "0.6.2", + "async": "~0.1.22", + "coffee-script": "~1.3.3", + "colors": "~0.6.2", "dateformat": "1.0.2-1.2.3", - "eventemitter2": "0.4.14", - "exit": "0.1.2", - "findup-sync": "0.1.3", - "getobject": "0.1.0", - "glob": "3.1.21", - "grunt-legacy-log": "0.1.3", - "grunt-legacy-util": "0.2.0", - "hooker": "0.2.3", - "iconv-lite": "0.2.11", - "js-yaml": "2.0.5", - "lodash": "0.9.2", - "minimatch": "0.2.14", - "nopt": "1.0.10", - "rimraf": "2.2.8", - "underscore.string": "2.2.1", - "which": "1.0.9" + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.1.2", + "getobject": "~0.1.0", + "glob": "~3.1.21", + "grunt-legacy-log": "~0.1.0", + "grunt-legacy-util": "~0.2.0", + "hooker": "~0.2.3", + "iconv-lite": "~0.2.11", + "js-yaml": "~2.0.5", + "lodash": "~0.9.2", + "minimatch": "~0.2.12", + "nopt": "~1.0.10", + "rimraf": "~2.2.8", + "underscore.string": "~2.2.1", + "which": "~1.0.5" }, "dependencies": { "colors": { @@ -711,9 +711,9 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", "requires": { - "graceful-fs": "1.2.3", - "inherits": "1.0.2", - "minimatch": "0.2.14" + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" } }, "graceful-fs": { @@ -741,8 +741,8 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } }, "rimraf": { @@ -757,7 +757,7 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", "integrity": "sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY=", "requires": { - "rimraf": "2.2.8" + "rimraf": "~2.2.1" }, "dependencies": { "rimraf": { @@ -772,8 +772,8 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz", "integrity": "sha1-lTxu/f39LBB6uchQd/LUsk0xzUk=", "requires": { - "chalk": "0.5.1", - "source-map": "0.3.0" + "chalk": "^0.5.1", + "source-map": "^0.3.0" }, "dependencies": { "ansi-regex": { @@ -791,11 +791,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", "requires": { - "ansi-styles": "1.1.0", - "escape-string-regexp": "1.0.5", - "has-ansi": "0.1.0", - "strip-ansi": "0.3.0", - "supports-color": "0.2.0" + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" } }, "has-ansi": { @@ -803,7 +803,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.0" } }, "strip-ansi": { @@ -811,7 +811,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.1" } }, "supports-color": { @@ -826,8 +826,8 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.8.2.tgz", "integrity": "sha1-3zHJD/zECbyfr+ROwN0eQlmRb+o=", "requires": { - "chalk": "1.1.1", - "file-sync-cmp": "0.1.1" + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" } }, "grunt-contrib-cssmin": { @@ -835,9 +835,9 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-0.12.3.tgz", "integrity": "sha1-QVdZYJb7dlb8RktMx7B0beHzkBQ=", "requires": { - "chalk": "1.1.1", - "clean-css": "3.4.28", - "maxmin": "1.1.0" + "chalk": "^1.0.0", + "clean-css": "^3.1.0", + "maxmin": "^1.1.0" } }, "grunt-contrib-jade": { @@ -845,8 +845,8 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-0.14.1.tgz", "integrity": "sha1-5nkmZdsC2kFti6ZmhAGjihaxYl0=", "requires": { - "chalk": "0.5.1", - "jade": "1.9.2" + "chalk": "~0.5.1", + "jade": "~1.9.1" }, "dependencies": { "ansi-regex": { @@ -864,11 +864,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", "requires": { - "ansi-styles": "1.1.0", - "escape-string-regexp": "1.0.5", - "has-ansi": "0.1.0", - "strip-ansi": "0.3.0", - "supports-color": "0.2.0" + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" } }, "commander": { @@ -881,7 +881,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.0" } }, "jade": { @@ -890,12 +890,12 @@ "integrity": "sha1-C4n5xg1OrSc46Ca6eyzKyaVwKr4=", "requires": { "character-parser": "1.2.1", - "commander": "2.6.0", - "constantinople": "3.0.2", - "mkdirp": "0.5.1", + "commander": "~2.6.0", + "constantinople": "~3.0.1", + "mkdirp": "~0.5.0", "transformers": "2.1.0", - "void-elements": "2.0.1", - "with": "4.0.3" + "void-elements": "~2.0.1", + "with": "~4.0.0" } }, "strip-ansi": { @@ -903,7 +903,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", "requires": { - "ansi-regex": "0.2.1" + "ansi-regex": "^0.2.1" } }, "supports-color": { @@ -918,10 +918,10 @@ "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.9.2.tgz", "integrity": "sha1-GmHG8hJBDkq7T3yJFTcXsQFWAmA=", "requires": { - "chalk": "1.1.1", - "lodash": "3.10.1", - "maxmin": "1.1.0", - "uglify-js": "2.8.29", + "chalk": "^1.0.0", + "lodash": "^3.2.0", + "maxmin": "^1.0.0", + "uglify-js": "^2.4.24", "uri-path": "0.0.2" }, "dependencies": { @@ -935,9 +935,9 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" } } } @@ -947,11 +947,11 @@ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", "requires": { - "colors": "0.6.2", - "grunt-legacy-log-utils": "0.1.1", - "hooker": "0.2.3", - "lodash": "2.4.2", - "underscore.string": "2.3.3" + "colors": "~0.6.2", + "grunt-legacy-log-utils": "~0.1.1", + "hooker": "~0.2.3", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" }, "dependencies": { "colors": { @@ -976,9 +976,9 @@ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", "requires": { - "colors": "0.6.2", - "lodash": "2.4.2", - "underscore.string": "2.3.3" + "colors": "~0.6.2", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" }, "dependencies": { "colors": { @@ -1003,13 +1003,13 @@ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", "requires": { - "async": "0.1.22", - "exit": "0.1.2", - "getobject": "0.1.0", - "hooker": "0.2.3", - "lodash": "0.9.2", - "underscore.string": "2.2.1", - "which": "1.0.9" + "async": "~0.1.22", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~0.9.2", + "underscore.string": "~2.2.1", + "which": "~1.0.5" }, "dependencies": { "lodash": { @@ -1024,8 +1024,8 @@ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", "requires": { - "browserify-zlib": "0.1.4", - "concat-stream": "1.6.0" + "browserify-zlib": "^0.1.4", + "concat-stream": "^1.4.1" } }, "has-ansi": { @@ -1033,7 +1033,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "hooker": { @@ -1051,8 +1051,8 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", "requires": { - "inherits": "2.0.3", - "statuses": "1.3.1" + "inherits": "~2.0.1", + "statuses": "1" } }, "iconv-lite": { @@ -1065,7 +1065,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "inherits": { @@ -1093,7 +1093,7 @@ "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-finite": { @@ -1101,7 +1101,7 @@ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-promise": { @@ -1125,15 +1125,15 @@ "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=", "requires": { "character-parser": "1.2.1", - "clean-css": "3.4.28", - "commander": "2.6.0", - "constantinople": "3.0.2", + "clean-css": "^3.1.9", + "commander": "~2.6.0", + "constantinople": "~3.0.1", "jstransformer": "0.0.2", - "mkdirp": "0.5.1", + "mkdirp": "~0.5.0", "transformers": "2.1.0", - "uglify-js": "2.8.29", - "void-elements": "2.0.1", - "with": "4.0.3" + "uglify-js": "^2.4.19", + "void-elements": "~2.0.1", + "with": "~4.0.0" }, "dependencies": { "commander": { @@ -1151,9 +1151,9 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" } } } @@ -1163,8 +1163,8 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", "requires": { - "argparse": "0.1.16", - "esprima": "1.0.4" + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" } }, "jstransformer": { @@ -1172,8 +1172,8 @@ "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=", "requires": { - "is-promise": "2.1.0", - "promise": "6.1.0" + "is-promise": "^2.0.0", + "promise": "^6.0.1" }, "dependencies": { "is-promise": { @@ -1186,7 +1186,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=", "requires": { - "asap": "1.0.0" + "asap": "~1.0.0" } } } @@ -1196,7 +1196,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.5" + "is-buffer": "^1.1.5" } }, "kuler": { @@ -1222,11 +1222,11 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" }, "dependencies": { "graceful-fs": { @@ -1251,8 +1251,8 @@ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" } }, "lru-cache": { @@ -1270,10 +1270,10 @@ "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", "requires": { - "chalk": "1.1.1", - "figures": "1.7.0", - "gzip-size": "1.0.0", - "pretty-bytes": "1.0.4" + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^1.0.0", + "pretty-bytes": "^1.0.0" } }, "media-typer": { @@ -1286,16 +1286,16 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" }, "dependencies": { "minimist": { @@ -1335,7 +1335,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", "requires": { - "mime-db": "1.30.0" + "mime-db": "~1.30.0" } }, "minimatch": { @@ -1343,8 +1343,8 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", "requires": { - "lru-cache": "2.7.3", - "sigmund": "1.0.1" + "lru-cache": "2", + "sigmund": "~1.0.0" } }, "minimist": { @@ -1380,7 +1380,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "requires": { - "abbrev": "1.1.0" + "abbrev": "1" } }, "normalize-package-data": { @@ -1388,10 +1388,10 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "number-is-nan": { @@ -1417,7 +1417,7 @@ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", "requires": { - "wordwrap": "0.0.3" + "wordwrap": "~0.0.2" } }, "options": { @@ -1440,7 +1440,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "parseurl": { @@ -1453,7 +1453,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-to-regexp": { @@ -1466,9 +1466,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "graceful-fs": { @@ -1493,7 +1493,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "predefine": { @@ -1501,7 +1501,7 @@ "resolved": "https://registry.npmjs.org/predefine/-/predefine-0.1.2.tgz", "integrity": "sha1-KqkrRJa8H4VU5DpF92v75Q0z038=", "requires": { - "extendible": "0.1.1" + "extendible": "0.1.x" } }, "pretty-bytes": { @@ -1509,8 +1509,8 @@ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" + "get-stdin": "^4.0.1", + "meow": "^3.1.0" } }, "primus": { @@ -1518,16 +1518,16 @@ "resolved": "https://registry.npmjs.org/primus/-/primus-6.1.0.tgz", "integrity": "sha1-s79Mk46weHS4crwrDOnA2oVdbBI=", "requires": { - "access-control": "1.0.0", - "asyncemit": "3.0.1", - "create-server": "1.0.1", - "diagnostics": "1.1.0", - "eventemitter3": "2.0.3", - "forwarded-for": "1.0.1", - "fusing": "1.0.0", - "setheader": "0.0.4", - "ultron": "1.1.0", - "yeast": "0.1.2" + "access-control": "~1.0.0", + "asyncemit": "~3.0.1", + "create-server": "~1.0.1", + "diagnostics": "~1.1.0", + "eventemitter3": "~2.0.2", + "forwarded-for": "~1.0.1", + "fusing": "~1.0.0", + "setheader": "~0.0.4", + "ultron": "~1.1.0", + "yeast": "~0.1.2" } }, "primus-emit": { @@ -1550,7 +1550,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=", "requires": { - "is-promise": "1.0.1" + "is-promise": "~1" } }, "proxy-addr": { @@ -1558,7 +1558,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", "requires": { - "forwarded": "0.1.0", + "forwarded": "~0.1.0", "ipaddr.js": "1.0.5" } }, @@ -1567,8 +1567,8 @@ "resolved": "https://registry.npmjs.org/pullstream/-/pullstream-0.0.4.tgz", "integrity": "sha1-Qdg8RG0pDi8uubaB0/O1b+6IoK8=", "requires": { - "over": "0.0.5", - "stream-buffers": "0.2.6" + "over": "~0.0.5", + "stream-buffers": "~0.2.3" } }, "qs": { @@ -1608,9 +1608,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -1618,8 +1618,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "readable-stream": { @@ -1627,13 +1627,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" } }, "redent": { @@ -1641,8 +1641,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" } }, "repeat-string": { @@ -1655,7 +1655,7 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "right-align": { @@ -1663,7 +1663,7 @@ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -1671,7 +1671,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.0.3.tgz", "integrity": "sha1-9QopZecUTpr9mYmC8V33BnMPVqk=", "requires": { - "graceful-fs": "1.1.14" + "graceful-fs": "~1.1" } }, "safe-buffer": { @@ -1689,18 +1689,18 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz", "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=", "requires": { - "debug": "2.2.0", - "depd": "1.0.1", + "debug": "~2.2.0", + "depd": "~1.0.1", "destroy": "1.0.3", "escape-html": "1.0.2", - "etag": "1.7.0", + "etag": "~1.7.0", "fresh": "0.3.0", - "http-errors": "1.3.1", + "http-errors": "~1.3.1", "mime": "1.3.4", "ms": "0.7.1", - "on-finished": "2.3.0", - "range-parser": "1.0.3", - "statuses": "1.2.1" + "on-finished": "~2.3.0", + "range-parser": "~1.0.2", + "statuses": "~1.2.1" }, "dependencies": { "statuses": { @@ -1715,8 +1715,8 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", "requires": { - "escape-html": "1.0.3", - "parseurl": "1.3.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.1", "send": "0.13.2" }, "dependencies": { @@ -1740,18 +1740,18 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", "requires": { - "debug": "2.2.0", - "depd": "1.1.1", - "destroy": "1.0.4", - "escape-html": "1.0.3", - "etag": "1.7.0", + "debug": "~2.2.0", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "escape-html": "~1.0.3", + "etag": "~1.7.0", "fresh": "0.3.0", - "http-errors": "1.3.1", + "http-errors": "~1.3.1", "mime": "1.3.4", "ms": "0.7.1", - "on-finished": "2.3.0", - "range-parser": "1.0.3", - "statuses": "1.2.1" + "on-finished": "~2.3.0", + "range-parser": "~1.0.3", + "statuses": "~1.2.1" } }, "statuses": { @@ -1766,7 +1766,7 @@ "resolved": "https://registry.npmjs.org/setheader/-/setheader-0.0.4.tgz", "integrity": "sha1-km7SjPdiFJYgkx566j8blYFuxpQ=", "requires": { - "debug": "0.7.4" + "debug": "0.7.x" }, "dependencies": { "debug": { @@ -1791,7 +1791,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", "integrity": "sha1-hYb7mloAXltQHiHNGLbyG0V60fk=", "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } }, "spdx-correct": { @@ -1799,7 +1799,7 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "requires": { - "spdx-license-ids": "1.2.2" + "spdx-license-ids": "^1.0.2" } }, "spdx-expression-parse": { @@ -1827,7 +1827,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -1835,7 +1835,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -1843,7 +1843,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-indent": { @@ -1851,7 +1851,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "get-stdin": "4.0.1" + "get-stdin": "^4.0.1" } }, "supports-color": { @@ -1869,9 +1869,9 @@ "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", "requires": { - "css": "1.0.8", - "promise": "2.0.0", - "uglify-js": "2.2.5" + "css": "~1.0.8", + "promise": "~2.0", + "uglify-js": "~2.2.5" } }, "traverse": { @@ -1890,7 +1890,7 @@ "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.17" + "mime-types": "~2.1.15" } }, "typedarray": { @@ -1903,8 +1903,8 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=", "requires": { - "optimist": "0.3.7", - "source-map": "0.1.43" + "optimist": "~0.3.5", + "source-map": "~0.1.7" }, "dependencies": { "source-map": { @@ -1912,7 +1912,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -1948,8 +1948,8 @@ "resolved": "https://registry.npmjs.org/unzip/-/unzip-0.0.4.tgz", "integrity": "sha1-/2fKhClbZRYdXH8vNAmJx43GCVo=", "requires": { - "binary": "0.3.0", - "fstream": "0.1.31", + "binary": "~0.3.0", + "fstream": "~0.1.18", "pullstream": "0.0.4" } }, @@ -1973,8 +1973,8 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" } }, "vary": { @@ -2002,8 +2002,8 @@ "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", "requires": { - "acorn": "1.2.2", - "acorn-globals": "1.0.9" + "acorn": "^1.0.1", + "acorn-globals": "^1.0.3" }, "dependencies": { "acorn": { @@ -2023,8 +2023,8 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz", "integrity": "sha1-V/QNA2gy5fUFVmKjl8Tedu1mv2E=", "requires": { - "options": "0.0.6", - "ultron": "1.0.2" + "options": ">=0.0.5", + "ultron": "1.0.x" }, "dependencies": { "ultron": { @@ -2039,9 +2039,9 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" }, "dependencies": { diff --git a/src/css/style.css b/src/css/style.css index d887cc9..8610342 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -10,6 +10,41 @@ body { -moz-osx-font-smoothing: grayscale; } +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 200; + src: local('Source Sans Pro ExtraLight'), local('SourceSansPro-ExtraLight'), url(../fonts/SourceSansPro-ExtraLight.woff2) format('woff2'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 300; + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(../fonts/SourceSansPro-Light.woff2) format('woff2'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(../fonts/SourceSansPro-Regular.woff2) format('woff2'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(../fonts/SourceSansPro-SemiBold.woff2) format('woff2'); +} + +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(../fonts/SourceSansPro-Bold.woff2) format('woff2'); +} + table td { font-size: 14px; white-space: nowrap !important; @@ -466,4 +501,4 @@ svg .axis text { svg .y.axis .tick:first-child text { opacity: 0; -} \ No newline at end of file +} diff --git a/src/fonts/SourceSansPro-Bold.woff2 b/src/fonts/SourceSansPro-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..52b6d6916a9faccb1cfbe604ce146443fd0ebefa GIT binary patch literal 15480 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 literal 0 HcmV?d00001 diff --git a/src/fonts/SourceSansPro-Light.woff2 b/src/fonts/SourceSansPro-Light.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bfb4050ba28136b32cf460af15c59a4a60416607 GIT binary patch literal 15764 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 S*EtNy_K%P~(Zoi`1^@s{kVmor literal 0 HcmV?d00001 diff --git a/src/fonts/SourceSansPro-Regular.woff2 b/src/fonts/SourceSansPro-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..efa300c564386e75fa0762d6a8b798442aa03711 GIT binary patch literal 15908 zcmV+7E(9P2g)#?;8w^$( zxQZ9pHtmC9w*%n*yWbRMgK4(|B})85BN2KWV67^%|Np-yCu0;~$F^x&-@_Eh>YU4* z$hbKJOWatZE(mFpEjArYJT0yLsz4}XDNlWL@yi}~-YxR_2O)MKL}do$Ur`EEA;>}9 zUzKh2iENRGy=2+EFxxn_r!q{7EKXq~X{yE}65;MNQZ)I8{j-z*dB^9A%r^VN8)XWs z^mur*VYSF~Q_|~AU#DS;!Vytv(fZDTIeG@Rjr>VYUig2q?d#mC>PGaNH;kHPE3t}4 z&YyM3%%Ta`6nKBmy)PL7rx_uni0KERc2jN=P>cPjv%V*>Wl2UEWJv5dfU}d#%+7uw zsOW$y#1^npIAGfYnr$1C zE-Lm^a0=A5V*LcfrELme#?MnZ*0|IH)`-KQP@$q)f4Fi_N zU`>ZXsi0sMW`X}0Xg>xR74OUImsRhFy)|8~!ZW+_EH`cCw2T?qGPi{DFHtJE;LwJn zoZ74vAIw<6G8jq#3$|2*$LEft@9OI!8>no8A_OMqa%yVcO-;C|NdV->mQzT+O#v@= z8(MQ_p{OMY5klVvwU9;RP2{8i{(1c8o?VH1S>PWAt_kk=1WWKge~|BQAFR75!5(H5 zh;BqI2b< zDeeFNshXeH+nuq*3z&;vO93rdPHDcb2{gq&V6kX*sL7a;7nC^SDz9|Yi1Fw4)mIab z%2>MD)^Qzq>sVGHcx&T7HqPc2)+O89t9wmEBuJ1UWa}|Ds*CosEyk|{@xQLkW< zCbCYMm`b7|l5w&n*fYWlLI$RUWSMLk4*dxV^w2$=R#nhuwTAI3)?JDr(WmZPSi$zd zu1I}}W?&fh1*)C9oB`u@Tdp2GP%wtVf(s+OB(mV#%gMkmwA+gVf2V)JuAXW%k{4tc z+kHdVWen|;$q?pu{@{=Pn%e*7lBUp;^Brnv8c_}ZKag;)+ zWK<$G$4fK{ZI*g-wLxVhO&Uvqo!UX|O6P&zHSNs0$lZwD=HSlbQcoW5Wp6I`Tiz9V z4-)VH5kB;h(#Jlp_61+o_?oY)ebaaJzUzD97woG1!Y}(9Kz^SX;$7!@5jXJMC~yKh1kUFzDUe(fSz->A z5fhWnbh6ud0xmrzvtrF4_VpBfeq$j#%S`dKMpB8aMUE5%=64rxOc^j(913igI42@X zDMu!{#-1jCtOs=K^9EI_vhZr0A7v(6&Yc$MRR!3qjxa|eqL4%7@u6z0#Wp+y%oNR> zX^MfK?A{23xb0gGwSlQ*{q6T*hPgR=R+t7J^0dqmegZ|A1oGLr>-|}#Chd>cy=z3ur4k4f ze&R2?nEq}G_E|Gq61Az>YS=<{RBFysU4`s;uw7xjoYT!oDxD_0gB_3IW4D5ycQO2QKwPdzTlb!>3MjDnLp_-h zu^;KB>Z*@M0$J{k$>>rdIn#5`^wgMW_KmQ)X3J18`&=v7 ziNlo5^z!5v757xU#Ld&$EzraIv_Wc~N}EEZxtK?aYJjvO5!qc3U2XI_OHtbU{N9Mw zk>B8FicXEP7Nd`r$tx3V;HSa-$epR{ZP?t;OWEpH`uieVvev9CmI~4g+i^6QvSak& z&N|iR4~30v?#&qki=AR;);%X_ z7zuV1S+-O_15z)|b(w4xd$-wK$PI79qxW~(1|aFn|GzxqS9!g$r=P7nW{=vZweS$d z&ENP(rh+bynE^Z_Xb&S|e!kHjU1{SDvt}I})cdZcsNQkA7dc#w=(&Vlb@Xjmq$7|c zAvQB5cjzo4C}LW0W!-1FF*6cIbCufor#mnsYg(~0c4JRE!T0;O6e$x?%tWgIsO%cy z*E#3Z&ih$$osGln<|TEpDbgAgK}pBm2l{&GW7v~~AKhqZaVR%G#a8Ip6ZY(H#5@v! zgN_FCAZH2 zGlPYtwJm@g0l)}K1^^(E$YgT4Ua8jV&5b528)((XQCv26uDL64v)5m98s38;7|CGu zNp87k1fV~L-z_zgGJQG8b zJl?ibS~7h9cOtNSB&QFX0RYe;;XK%5+dW?eNKgXUt_7eFOqI3!$~_L(#6SfOj}}x6 zoj3$`Mac$00|`L;e+potOyJzR0Pdd=%8`Jr5y*rGbiCAZ7RjacwW}abpZw9ET`Ed^AnCi1?TJ|8a!-@E9aMbN9hP z_);o+4yBxS=Zuyqbl=>Zkt_9P3i$PSI>6xX`k(D~2g8X+ z`M1p~flK#un(g7nqxk#daD{vO2tYW%BRl~jg2WjkQk2nUnQ2Xk$_4{O8WD3H7-D4g zC-2xOmUo?X&UqJHbjf8`Ty?`u*IbW+>d$k{L5B<&bl4F`9dq0%r=4(82#&MO0Pvt5 z(J7^Q>f^%BNKc-r+~9~-F!})qh;fK_T?HTkV{zKnQ#{-^G*X?S>1p~&hVJ<+fI)RTlnx}pUz0oWJ;aFgZ@e*ivwQ2(d4kgeKn zig|2}1tv{d25dB>*1UQRpx55oZo{-iGc>1}W-XYbhXUJB?zrWybSqqIz8!`QTjz;* zr_e5oVbz$xwjW3Eo_c17OeSU)RyKA|4U)wrTMjp`5n5HLR-;y(de6)?(kP9ZG#jmj z({KxQ>d~cJuMCK?y*C49AV7c!pbpf5t*8riVHfH_J;+0Ss1LW%02;t!G=zq*292N* z>_lT|0%y<^nnDJeK{I%c=Fl8Aq6M^oqi6{&VFOx0D@Z|W=mKle6}rJDbcgQn20fq$ zyhcyx32)I0dck(|MsMVz4<;Z6FcA}xfJvByG)%^1Bw`At;60{dDo$e>rr|TDV>N2P z8mvJQ)?zJEu@38yjP+QL4>*NWM3Fd+)7XYHID`8*i?g_c1SH@V5|N0zNJ0|Qk&I+y zA_Xb>Pdel%WjQP>ymOK?SPt1l6d<4xGaUbcBnzh>^I2>lla| zxPh0riJKUNTeycIxR3i7g$H$qkh-LVM@0f!h_<>jWiJzE@U-*Xw_>ccs zjyU32N+co@VK$MQ$c@279wHCs5j#Wd489V(PwYN^5_>@G0lpF15Zd85p&OwGb`yFL zdSO4IA7KFY5(W_l;Q*nEP=!;3(Fmhq3t=9@d^kv0Nmz*ogp&y;qnPkC;c48XZY%1x z!VBtlpl$~|6r-S|VT|^YH;HH+6YXO1ZZXmBT+!}&(e8cGHNeCNA#&^6N3d((Mc=2@ zz;N^>5`W}NU4TtYFxrHyk_#bZVhz~%N?m|YOk(zo)%|IiP$zobTqiNElQ{>5(_Xe& z=zUFOJZ~FW-TS6^DVcw37DQfMKuAad8!-*xmMv|ylK*$4Lnm&a1L>Jtr@bkkADX;0 zBvUDj`1R~3^m;}S8KPk-wK($Jys@<0mE1p92D!50^Zlf$N05I( z!m;^n6(DPpf>@ZL9!P0qVZ3&L#^bbF-~p&2gfABJsQ{K(cYU&sm0@&LQ%vl@U9 z$KGE)CG#K{!$7NzritNwp65}JFXG@vdOP}9wYrQ)7j;2#AE%D$Ser*|s45c|rDyNT zv#?V<_Fkx7DcBxs}5HW&AkE0gWv>Fvo{otpk8RO`V;8ynj}r(AR0&MkPF3PCB& zDHWtV-_Xq(QG8ELp7)H?gY{C>Qmun#AM!=3qfr~({|Nz2O+lk^ihovU=G%d>A;%AGuOM)06J})n7y_PB-l+aBR5K36MPVeNwLVu zyrQt64qYbl(08GPCnZ+xF%4=%!{@n`w+Vf|J6+0F806^%_10QCO+11Yhq-C~u8rJ) zW9b=>w^@eM7vm_5mP921brb~MMNCjj;m%xBR=;{fdUFts1J7R-^AYr~@~sciW9)CK zo&QJf|pYSkyq;lG-&R{E(M zAmfFp;z3$rw}PbtnF$#7K|QlFtfb`TH8-KY&W9-S7|tag&$sEowa`0oBE93ub^<;fx7F+uBJv zPnjZW;Gb98>`xoYPC^Apw_eVIzIUlHYc($2SA8*jV)TOy5|qW{wqvJ{j{c(`U69Q6F_2`^2g zpc#1RWtR!CLzgR-K%vSo71Q3i9{WVM-POcw6-a05s ziSs(RA)k;R)#rSb%6!}XOs(W;R~lC9j6D5AN$iNQ>^ADecQY^zWWqT{ULn{E+DsYB zJBo(*N`56Uo1IZ}S^kpjPkOaAU{%pc48etz{c@1j+Fmin@7eE|m4O#U76<9EZV zs8Y&|!d4!{UkP~f4VeadP)uI210!wmQXE(G+KB6C?jd6fABHgN5#ETPsfA=VWGu!g zHn`I7#+KI@zLRGXb?*Ot;fEI&fOu9mk5EUgQL2Nf`zQogMihz`%UkL{N zt7^=-`?2RyOawwlABrpMY(_S*(Tu5M{;an{BVsrQYJVl$b)1jR(5Cs%;@i@ZJR3n@xICA&Xb-v z)0y@e2FaRgh*WF{JW$gRocYveCH>)MOCtjtbK~goB}aH=x@>*El_@Y)xh*AeZr`fJ+h^t-c+~3tW6vu2 zEV`ionDgK3AOIzqTFQl5rsQ$~ictU)b!4@cV6>TxcvbNw-ol zUAldWpU%FxmINh^s5oN$PLFoxM$kg+GI+f4bkJU6&rtkLe~4e{m!p5tpSD4s1K~8W zmnk`3C=zNc7fYnwYrgLfJffLneHjSeCn6fn+AUoL>%+j8W|m=IwACff;kTfL`L52A zE05CkGG1!4(D{_1?6py8UbYOZD5c03?B9kSni(tX7M%pvDvCT0SN$M>sdX%b6H^4r zG=kCWuQt$?@pYN`Ipy|pdE>fG|VeU_RJsjGkTfO2V*lxKf!MSLqj z1r@hnx`+$;!gfPN1?k3wzj6(?vdC&M;GC_0^Zz=6X07)8Oohy?dmu$g)`vnYq=7Nz zc?*dAD`LoWHI1Z83i&ut*?{bjpjy)&m%hnW(+gWyy!9~|pE~2BG$eU#;Yp&LpEst+ zf5)YJcnY13<0h1WF`=a~%<)4E^U2c7{-rmu*bpeV2d|xfCzCX2lb{s&(K_A%Q@MKR zu7{Rlp|xqVFNl=Es{E}daI#7+%GckC=BASCmkO}6RxCRPXWjA!Z^Dd3zpwKn#yzq* z3Z!YXD2LTm>cvDdW!584wj2)PPcq3pW#H2``W?xtT*MfRwdTB_AP*dzOKMeg6EdR; zafLLCtvat(sl?bqNUj#Og5FUpd4XNz7b|2ek<^Kj-4QNR)WtG3T@dWWcLZm8=6GLd zWMU1mpEC#=`*Wo=0i=&fogAonmD#ka(z#IjI+DilmRrgD!6fYTFM8gQ$L0x;_q2#; zGYQB28!<1N1e-Job+&rYpXWQaUI}*%2>7BC0lg;$0`T-zfwSL0{>0lx_^DgDuzt3g zsoR9l`*?^M(tDAs-F!<5cZy_?@D6}k!Rcly8g7^vYsq+5Kzt8hPI;3Q*kfx>_An1NFD&aKOKC? z-NFNzyX3)=kqVe)ilho5tCF2U2n)5NUz~c6ZR-51^GV?Hm5wKk7e)}vPZvcW~{Ioz*AO}=c^BsPuGuy@Oa0Y5q)R}q0tEX3MDUiTUml^P-N)^6LVze;? zLNoLI&4yBuBCl)HinYCKvsmp;ZzIp<)!Un!W_5HlO=-5v^19khtScYQA76{i&Vy6z z*H5NTOnpA6ZQwio+|Fzlufr7>k)ox}d+hl2_AD(;EOyaT4aEP_TW-u|$Y_6xw#_l# zO?q1mIh%H#L{Xx*%PSMftaQ-37&pOjikgG|CYns5v7hx`g_3N&1`=1_TPr-?QgrF# z%cX@Uy`!dHt1QP!W@%B;QMemv*p1ko^rq*y!pg3!T3&c97a>_P&XekKpGI)Ql2~ow zt`pP$a;8aD6`+i^9L2v+naM4gexE$8 z-UG>zh@0P^Rrb8D%VO`aixi{8>B`r~|41lWn=~dlcZ4%XrP1a{oFfY2Kx3<<4?{2F zNwns4AtvNpb6p|3_H$q~o$+Rb4a3hU=h03-u#i(ybz(l6{J%T3fHgo&GtpT@{h}Pa z^>^DD(<9Rvn?whS{dkp*R_~hRnUaBWEodQATGpdn8B?++xoGt&oewX$aeYB_yf7gqW64v&2x5J!3&d+3abt zmR3Y-yrs2d_UO1H?%kOM!QL}!k>Uddjk;x+ermdn3{S zLCN}(b_#WFxjfoMR{RGRG)!sFpcW~#b{Yf?eT2IQJm(BG@QXG!+CbfP{o9M_L;{qZ ztcQZe(sm>$@={eAT481;y(m-bq(Uhc5{U6gVSIWy-Fqp!VuW$1QLOVXlCko?5lVk zijl;;wMAV4l#^ITK50;lVZrbV*d&xvT;%i0l~nxKJZ##oWY^_SIQbzi_mCX->9UJF zhBmR?lSst~y|E!57PTd_Z2TGSbM6x%#;!+kF2cled>6T43wpythcmRCEm zax*9xBd>BdBt48ogqLn__Hf;g4Pi$3ds_-G?a_-|hnR1-q%5SQ>TD%@pTL^c>lsoV zs#@m9g8XcXQbRAwREC&Rdo%eV()yK|NYjI-C#7o=^$?V3(5921Y7-3yU$04*@l8p%g;RE~< z9nzuOdnFVBX6LFutpf0QCK*JijWh3+#F2EOd1=;bptO*|oBmNp;t4;K6Epstkh(%X zaW#ohw&@lt#X;&XpBx~kY{4g>Z;UXnG5#u#mr37s|RuL>h#a;$zTq9x9-NDt4CUH5g- zlUz+*&)AcQo?uUUoqy5WwI6a#qfW2Bg*esTuN`I0y_T?VU!0~<8VT86_MCX^D~sNV zHf=;~NHnkaM`!oPocuc2W+w5zkN#8dSkBl8y^%5|v$fBGkk+|=4=h-1LSA`le)^hh zZaI3T?8x{mu*RfOyKfrvUQ$|Ab-gual`{K=A^4fnWRdvweD@3E-QP(q42Lp5=D1Ds zkDxH#^_|#?>S(mL@N&FRd)C_C-j(ZT`EGXWg%QFrZBsfr+h+R68g3SxoIqb@v)29P z>#6r(sbFbtUYBRYXnAhpE2>2pqqw={fq&TkxuB;UF)Ik|BHti&m7Oby0X}h04_jf*LvBNcxQ47E&v7 zs$m&&u1isapY1u0a{Nc zoE~5wy+ot#1P_y$6CruJBkO}3UQ{`%h;?SUfyms)J%B}DJ;2#}noagC|FJe2gq);7 znqMv17%XFOUovr-f=6@z2TSX>ZQNMjTUrvdc)_}@Sc|_x)+AJz zObO+&m+|fFjIAD@|LC@HF$y|5W`(5!s{GGC`Hc(?SjgRe-ps^s{rcg_TbT4G4piNgqfkg#>M zOM7)eo&qu^vjI7t9Ul0=tsmojZsPF<}t>tMBAK zbAKta=D%$nba2xMbf1r+vszV@KTZrJiPh%+;s@)82plsin`o0tX|8?;-U)&N7bD$4 zX>yjZrt7_arci2Q_T7-z5h()?aaDl*mJ4Ee%1X;q2sW9Xz|^3dZ-tQ63UemO%zO}D zXe!a~hUcP|Leq5}DO#0zwIt1Kn!=emYz4d^^&`l4U`Bjrk_=HB>Je<2Nx~TTq(!kH zE&Anr1}0|4o9767=VJ<)K2&JO0M%avG@(Kx<1ZHw#xAhL$kGf-F=^oKb3(4zz{A-! z38l|vWE1OUc%iviiJEc?PEsq(1g*ruSaVZePoxg;HMnZPaofdZdrH@vT*nN< z5r$#K6+o$?Yd~c?;(iRt51#OPqJv|$5o36n zvVd}QFbI*uk|HtK2Qj`Kl|c)a9Gd(QjU7S}h`da>KW3kH#wr!oRJN{eT?+=a+y-A_ z{F%=kLH2$1V|5JsSH*k#SrM@VkHrQROid1%NO7{TSO_L9*Jnr|A_zh3MHYQ6wwwAPQWED z7hoMi_=P=J>lR56ClOY_BMx4^!Agw?NC>KUDJDkN9*5!c$vD=H%Y#I2ox+>JG5>{$qgUOfFl22*B zYQq0^`7a7}+%6ODx2yk+J|qt?9^q%KX0y){@Y61v@#p8J@VDZ=NzYyV=2jXj%C<6MutkG6{B1!$d=k)z0F8w&oryx_Of!be{g)y!n2l_#Tck5_c-YbRLV8n~ zX9+D{^ot6VLzGFaGFq!S27QOTv^;%Y(8_CcIUCrTlpJ(owpZK^CSP2KUw7w567dZT z#0%TX^UxQw6@i4szVrfQzwC77X{df#A}75ZQxt6AyV%94OPYk3Iv(h$tM`M3?D~rG z>^g%!r>?vrr(P#!3bLl0z`2$J`an7i@-HBw5qhY$j-K9DX zJHw<_;XM`RH$SBE_JTqyRI&j}B$01YsqYmWNi`8)N=CNBOV^y>U@l|j7+TR#IGKgZ zD-vWrsM$m5`C@sSo|0a(dFe{e@WaA)D^rU_*p-I9qbT974AOWStv>o9^*Gq4 z0h#5^lZk)hOh?&UxFV~MH^JxSb@rXkBaheVLs35H%la!n#`HS;b&~hjTwbTw$DIHM z!;@AfBUdIR%|a&6!U~%|+(+Tbp$YqvlMf_f_R;wwJ$J@rzMCs6l2=E?t)O8mGVA6W zu&hkEQGH5Wfe>Mjv3h-u@H2SqUD;2QNmZ*l*zC^Ll_XN->P|MhV^!7f5MLveKZKw+ za%qYN^+O-#I9Wv?swl@XnBx=`k)R?UpGR3sW2~i6)-q^oQO2r4wI+;1qd{S6?V#TH zK}}dxsy7a5v|;Hqnj%c28Pprf77;XmjX%TF-QsrqHDf#(=^=XR;P@Ifp{1t&Q=U-jdE$r5I z3+8pJ{m!kA@VfVi5WMb@bE~&UJzvnH?Gg5@t5<=12l*&FZ?=Zp6EQ3@B0fBW_hB}t zK&5e0M0_W&E7lrM*11Zf{oh0(VX+ZWi4pgOx1+s|Vilu&5eRyOjq_!CWniwWK^+*q zqUMy9ZpV9MQesZNmAtFYQdXV%BUsy;R@;ldTYa)$)qhg! zH$k94s_m+n!j8dJ>sGBTm6hw1wX2+!>%sb|+ZRw@(ege~s8=ZTD`fRS5#`F{zFr+d z%r~6VLXkGH3gY(C(EtGtpwR%H03;4TB^&_Mic_*U z=>-=1A_@5m9{%sYB>I0F^XDC8Qt}VnJQ-fcDkkx~5US=!r`2E*0;Kp~aS(8W%$7JH z7DSfT9t{(B@!$qopx{SU`JXA=APW>UPNS^W_{6S*xIt!12#OSNb>IeBprBaA@>=kp z|0xVyr=~5~BNAekQd!C3ZX~!)%|PB%e#QKE)}mZ5HGA^P(Iz7mO6bNpu2a(%@G2B= z+F(+xIq?~8xz2# z-az9GSeXeoyJ~|hzujhCysSuWx9%2m7i+9xQhMky(hN_pia3gw@Up3yEQWCuFX3gp zf>-exUdJ1F6K~;ddFK}Mxytz$yXFsj#%LI1jE89iaI58fQ*m&gN&c{xvsO&m(HtxW z06H;t-uIy0pQsnMw3l^t=96jcQExN@0S||$W*)Tz;1?I*|6c3g&%f~xz>j}701ScK z7hjTo0KkJA@a2$AvQ_5y8b!Lq;@lc}0DW(DgKR40+ZO=C8aRzC{QJh}$|?IoQC|=8 z0B(}ElJ19A7H*JDgHZVdAjJi;X+^$$N8fQ@L3U3Jw(6fFdwV^!cVhc*q%1Kz^B&^` zT$mVa(?3gh?n?mAYGQ>IwP25o&RobU02O9&1N23&#~N?pl5NvJyfQs#-_ivrf2_a`?^Tl=T7YBSjD zI%?0x?lil(S<*!|7E(vw=wD*W!KndOy$P@>eP3X-T+-GD1OR@)v!0^RKN0}?>{l;` zl|U!c(KifZn<%@00MIv*N>|XqPeR*rR7Ttaz{L*?&28sl zX1e#QBZZNt*@F|RTpcQCNPY(Em*@YHH8T6U)eilgM68L8(;q2l2Lb6{Qh^BqH4iL+ z%)?2?1tVQ3(u}+h!jrZsc=xU~1h$~<@V1n6Tc?Z`*vRbc?nW+nxj_9#YY+hw#J8&) zPK(Y3)l~n>;{hy3A7yX|&?hXQ)a`r55mpo}5;-DCAdwO;749MlMQOLj?uz^(-Ze&0 zCyfC3Wq)S4eWxw&VFT$6dn6A%!$lO5TB4LmMKDV*t7IvtkYI8Mt z_Wo$hshT@=AO;Wyt_hX*3>3HHRRQNYUmR^#Pf{IAw1KithyEv^hE{Sa1wKG^a1{fT z-b*St08aY=M;e9DGQ_*ehTkO>fVAB}%mYGYW(_#zmD$L28WMLGvc(e$z=&uY#)uyb zSc*#+9-y!gdmE?7vuF@^L)3{#S~*B>-($ULNCL!&zf1r~c1XBF$Tei|);-H=MwMC2 za)FF{sI7xBN+_w>*R~mfz_Jx07Z9x^H|a0kmZ}~ViS!CUb@VEFC)Y{>SKc|EmCAyA zmErp&c5kIX^b^{Kfo?lk@iTz#S4eaULTf{@0MPryr2^2VEX(i#O@Tb}4{4xUj=FzV zE0my*@bLqRVLDgv+r#`z2OyVnG-vP6JJ@^8LgEDoBN!T>-KJa-y?`Hk6&XaNinC$C zl@-VZxrp;s$ehs7mGBaoon=yHd<1!eO`kbj2d?HGiLqMgR7g@nln}x+Tkby`%+w%X zc&VZqGtG>GhcWg+Q7bkW3^Ju1VC;aovau|Y+0ZbQX4Y(tjZlr+ox^+pag92fL!WNc z%jsaqUOO-aMcJbb1tw2prM`|YYUX9#}pu8T~MO{MAsO_Us@pMm;d;6y)yvH z-Sa9U{HkkW)v(0*He~Q|S%C>;K&<4HfcVaF1qtazwdP5^53QUR=u)5lIXv&qY`z|a zsGgf)LY#O_?lVlKp9ow(C1C08LY#&BfaP?bO~6eG=?2V9k4!GcjJS0tTM|ZycBNAW z5gj7*ihg!p8)G@Jw5~jEf-9a@toUT8Mk+4hac5nUc|O@}Cl*fO*P66O5c^~|iANX_ zcYyW6QKD{~W03PM>NPoQAwkr?fS{gd=31Mz?mSe73l0ZSC988)4vx>4FI%{@&faFU z=23&WeJ+h(>x-o+5hC^Y=pCd-00zh9t_cRvsS|VD0o!Ay==T-Ji~@6U7%jL7(Y$hE zVf)F70H7(jpcE(TT7k%@y?x68rN14bUS4N-;!B~tK%4S;8|GrNS0LEU$ zrK!w9Meky;F-&*M@y5xfRqE@fJJiEm(?Y_93a%Vwm^%Z|A6x~&okOF(BjWd#D{r}--sdPTwt=0{t|oC|0<1cEN+(7n7)`J#8~{YV9Ec=I1R zd*sP;_52ynrRI8^jGr^sHzy~1owf##`oI&@Jl#_Ncv0`jYEf+}pzbq(u*S9uu{gV? z3Zr;)Je<0A$IT^G3kk$EwGR#VK8UiwrJ)s0j}9l_l58c?`qN!=lC-7`^C zOrMg0<4>J7Q6t`XD(yXGgUp_`)O|Fr~2ZB#=KOjN}S|Z z^VOwzZPV*3zU`uV!z~KyGX!xKs6p$2WCmG={SOfs5>RA7fkO?77HrbTl&kQ}oYC3v zx-Dz(CFIE;XYygxRG|n|WdoZJ9m_xzWpEJiH zZZKjdRUr@{DqWY6A&Rg7Tgs$<2(1)xaa8HF=C7z}?71~L=}2o&HbLEwSW%$kQOlU8yd zX99~vU*s%b1#2cwzs^9#jw{BGtem?>u5$pF0CyYZH3Mm@V=#{WdChAd z(OiGRryn6z5B^x=cLU7eD{{8nf#R$}0u>Fu(*z0!-wLWQO8R#HYr@a}q~+kwIVt5L z$Xh9)Lv#Ut$vymw-hUR!8*bm7GD?4Gf*32@@kYL@N)LS8(CBQ>P0{XC=o}GSGlKbr`9Qk;$}C)~a$Z1UTi=nGpOD2T^JYHbcE%3mlo%d_W6`AHz%@-xU=TIE~)dhwc$E3{cY#aD%H7hlX?}%p`jjZWP~##=P1@Zzo{<6$*g&%(=jniN zi!sgeiq-{LcH=&ED4f-EF)|#HM(j9uF-SpXquh0s{F~cm(x6QYONU)#@X&HL6(GJ@ zRLBInL#_B}0u$jbv_Khj@Y#Tk!G3@>LK~ce3s4CS-~ktmgAq^zi(tL9@w~hM;4%Op zP@d~VbE;4TKo%T22^;}wjsr&_1N;am`oy3|eU2i{KF`ub_XQ@$(HC)Y+WTV0=XGU~ znMI=?f&|)*NZ1)PI29I0b>Hy>D_$~w$obtp%5+%R@ z38_xb>=5yzRCt0vElteEghmk5h+(sqtyytsmaQ+?qR9{zlBQYfQd}5uB8G*jYQl!wgMqLc82?%WXAY zc;=NlwdxJmV1x}uYBWldX02L`HpX3JwQDm@hw(PrZI%f-O*F|%hdlQ>A@T}}$j~N9 zG9(l<3@jYH1aS-?+6KWxsJcZF@q+#K`N=7#9dXnaTg4}gXY6&-3_2ir7SkwFVwhrT zPsMPlndX>{CQK=%l~GnX>s!^_z#^TT`i|Wfspn+(4ZhgnVz<+m zO8u&QJ@8sS4?N44ffxG*+uVos&Gxf2;92GTkdY3&l@vyeJB1$W^AsM-4m!Ts`%nnp zhxYj2>)-DUa%jjQH~u`(GE#{TE?wX3%b=#sr> GJ^%n7S96yD literal 0 HcmV?d00001 diff --git a/src/fonts/SourceSansPro-SemiBold.woff2 b/src/fonts/SourceSansPro-SemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..e379beda77056d14ad4e3ea8ab7883523a41baa5 GIT binary patch literal 15784 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 literal 0 HcmV?d00001 diff --git a/src/views/layout.jade b/src/views/layout.jade index 6750f97..af4d88f 100644 --- a/src/views/layout.jade +++ b/src/views/layout.jade @@ -5,7 +5,6 @@ html(ng-app="netStatsApp") meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1.0") title MIX Network Stats style(type="text/css") [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } - link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700') link(rel='stylesheet', href='/css/netstats.min.css') link(rel='shortcut icon', href='/mix-logo-thick.svg', sizes='any' type='image/svg+xml') link(rel='shortcut icon', href='/mix-logo-thick-1024.png', sizes='1024x1024' type='image/png') From 0626ecf41544229b31dd89db635d60f58f017fb1 Mon Sep 17 00:00:00 2001 From: Santiago Castro Date: Sun, 16 Apr 2017 16:38:29 -0300 Subject: [PATCH 13/48] Fix broken Markdown headings --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 48efbf7..e2aeb37 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ npm install sudo npm install -g grunt-cli ``` -##Build the resources +## Build the resources NetStats features two versions: the full version and the lite version. In order to build the static files you have to run grunt tasks which will generate dist or dist-lite directories containing the js and css files, fonts and images. @@ -41,7 +41,7 @@ If you want to build both versions run grunt all ``` -##Run +## Run ```bash npm start From 75bf2f5d45d0e6b26e9754863c405ef50113991d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 26 Oct 2017 14:07:13 +0300 Subject: [PATCH 14/48] Add automated docker hub builds --- .dockerignore | 1 + Dockerfile | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f3b6411 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +**/.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..36d6e0c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM mhart/alpine-node:latest + +ADD . /eth-netstats +WORKDIR /eth-netstats + +RUN npm install && npm install -g grunt-cli && grunt + +EXPOSE 3000 +CMD ["npm", "start"] From 4a879a96c48899b4ec30c262bdb34d12c9f447d2 Mon Sep 17 00:00:00 2001 From: Ayushya Chitransh Date: Tue, 13 Feb 2018 14:44:21 +0530 Subject: [PATCH 15/48] Use latest version for getting location info Previous version was returning incorrect location data. I verified that using newer version gives correct results. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d202cc..f675d90 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "d3": "3.5.6", "debug": "2.2.0", "express": "4.13.3", - "geoip-lite": "1.1.6", + "geoip-lite": "1.3.2", "grunt": "^0.4.5", "grunt-contrib-clean": "^0.6.0", "grunt-contrib-concat": "^0.5.1", From 43f5d657666d80eb53056f6235819598fe873760 Mon Sep 17 00:00:00 2001 From: Ayushya Chitransh Date: Tue, 13 Feb 2018 14:52:45 +0530 Subject: [PATCH 16/48] Using corrected IP address IP address being received had `:ffff` at the starting, it needs to be corrected before setting correct IP for node. Closes #99 --- lib/node.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/node.js b/lib/node.js index 8e4f9ca..454fa54 100644 --- a/lib/node.js +++ b/lib/node.js @@ -102,6 +102,9 @@ Node.prototype.setInfo = function(data, callback) Node.prototype.setGeo = function(ip) { + if (ip.substr(0, 7) == "::ffff:") { + ip = ip.substr(7) + } this.info.ip = ip; this.geo = geoip.lookup(ip); } From 31a3f84214cfc371e680e17c8ba794b42f0c67dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 23 Mar 2017 15:21:12 +0200 Subject: [PATCH 17/48] Fix block history if chain is shorted than MAX_HISTORY. --- lib/history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/history.js b/lib/history.js index f71d61a..82cde66 100644 --- a/lib/history.js +++ b/lib/history.js @@ -169,7 +169,7 @@ History.prototype.add = function(block, id, trusted, addingHistory) propagTimes: [] } - if( this._items.length === 0 || (this._items.length === MAX_HISTORY && block.number > this.worstBlockNumber()) || (this._items.length < MAX_HISTORY && block.number < this.bestBlockNumber() && addingHistory) ) + if( this._items.length === 0 || (this._items.length > 0 && block.number > this.worstBlockNumber()) || (this._items.length < MAX_HISTORY && block.number < this.bestBlockNumber() && addingHistory) ) { item.propagTimes.push({ node: id, From bc4b0b9ce3c54ccf36895ece10b64d0ab043d707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 18 Aug 2017 10:51:48 +0300 Subject: [PATCH 18/48] Log IP addresses with blocks to detect spammers --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 676cfdb..04fe8e5 100644 --- a/app.js +++ b/app.js @@ -196,7 +196,7 @@ api.on('connection', function (spark) data: stats }); - console.success('API', 'BLK', 'Block:', data.block['number'], 'from:', data.id); + console.success('API', 'BLK', 'Block:', data.block['number'], 'from:', data.id, 'ip:', spark.address.ip); Nodes.getCharts(); } From 82e2fa36e1accc06f008ecd773f5d96b60e47284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sat, 9 Sep 2017 17:07:42 +0300 Subject: [PATCH 19/48] Log total difficulties to detect spammers. --- app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.js b/app.js index 04fe8e5..150d77a 100644 --- a/app.js +++ b/app.js @@ -196,7 +196,7 @@ api.on('connection', function (spark) data: stats }); - console.success('API', 'BLK', 'Block:', data.block['number'], 'from:', data.id, 'ip:', spark.address.ip); + console.success('API', 'BLK', 'Block:', data.block['number'], 'td:', data.block['totalDifficulty'], 'from:', data.id, 'ip:', spark.address.ip); Nodes.getCharts(); } From 4e9492fc83a97a7948b52aeac8a4839bd400526b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 12 Sep 2017 11:29:03 +0300 Subject: [PATCH 20/48] Introduce an ID reservation list. --- app.js | 5 +++-- lib/utils/config.js | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app.js b/app.js index 150d77a..0e0cdd0 100644 --- a/app.js +++ b/app.js @@ -29,7 +29,8 @@ else } } -var banned = require('./lib/utils/config').banned; +var banned = require('./lib/utils/config').banned; +var reserved = require('./lib/utils/config').reserved; // Init http server if( process.env.NODE_ENV !== 'production' ) @@ -106,7 +107,7 @@ api.on('connection', function (spark) { console.info('API', 'CON', 'Hello', data['id']); - if( _.isUndefined(data.secret) || WS_SECRET.indexOf(data.secret) === -1 || banned.indexOf(spark.address.ip) >= 0 ) + if( _.isUndefined(data.secret) || WS_SECRET.indexOf(data.secret) === -1 || banned.indexOf(spark.address.ip) >= 0 || _.isUndefined(data.id) || reserved.indexOf(data.id) >= 0 ) { spark.end(undefined, { reconnect: false }); console.error('API', 'CON', 'Closed - wrong auth', data); diff --git a/lib/utils/config.js b/lib/utils/config.js index 8222c64..88768f9 100644 --- a/lib/utils/config.js +++ b/lib/utils/config.js @@ -26,6 +26,7 @@ var banned = [ ]; module.exports = { - trusted: trusted, - banned: banned -}; \ No newline at end of file + trusted: trusted, + banned: banned, + reserved: [] +}; From 592a98cbcc4044e3b3241c6de3f747ce5a7c52f4 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Wed, 4 Apr 2018 13:59:43 +0900 Subject: [PATCH 21/48] fixed mobile layout --- src/views/index.jade | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/views/index.jade b/src/views/index.jade index 6b14bb2..697f6a0 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -4,7 +4,7 @@ extends ./layout.jade block content div.container-fluid(ng-controller='StatsCtrl') div.row(ng-cloak) - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.bestblock.text-info div.pull-left.icon-full-width i.icon-block @@ -12,7 +12,7 @@ block content span.small-title best block span.big-details {{'#'}}{{ bestBlock | number}} div.clearfix - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.uncleCount.text-info div.pull-left.icon-full-width i.icon-uncle @@ -21,7 +21,7 @@ block content span.small (current / last 50) span.big-details {{ bestStats.block.uncles.length }}/{{ uncleCount }} div.clearfix - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.blocktime(class="{{ lastBlock | timeClass : true }}") div.pull-left.icon-full-width i.icon-time @@ -30,7 +30,7 @@ block content span.big-details {{ lastBlock | blockTimeFilter }} //- span.big-details(time-ago="lastBlock") div.clearfix - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.avgblocktime(class="{{ avgBlockTime | avgTimeClass }}") div.pull-left.icon-full-width i.icon-gas @@ -38,7 +38,7 @@ block content span.small-title avg block time span.big-details {{ avgBlockTime | avgTimeFilter }} div.clearfix - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.difficulty.text-orange div.pull-left.icon-full-width i.icon-hashrate @@ -46,7 +46,7 @@ block content span.small-title avg network hashrate span.big-details(ng-bind-html="avgHashrate | networkHashrateFilter") div.clearfix - div.col-xs-2.stat-holder + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder div.big-info.difficulty.text-danger div.pull-left.icon-full-width i.icon-difficulty @@ -62,58 +62,58 @@ block content div.row(ng-cloak) div.col-xs-12.stats-boxes(style="padding-top: 0px;") div.row.second-row - div.col-xs-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.active-nodes(class="{{ nodesActive | nodesActiveClass : nodesTotal }}") i.icon-node span.small-title active nodes span.small-value {{nodesActive}}/{{nodesTotal}} - div.col-xs-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.gasprice.text-info i.icon-gasprice span.small-title gas price span.small-value {{ bestStats.gasPrice.toString() | gasPriceFilter }} - div.col-xs-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.gasprice.text-info i.icon-gasprice span.small-title gas limit span.small-value {{ bestStats.block.gasLimit }} gas - div.col-xs-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.page-latency(class="{{ {active: true, latency: latency} | latencyClass }}") i.icon-clock span.small-title page latency span.small-value {{latency}} ms - div.col-xs-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.uptime(class="{{ upTimeTotal | upTimeClass : true }}") i.icon-bulb span.small-title uptime span.small-value {{ upTimeTotal | upTimeFilter }} - div.col-xs-2.stat-holder.box + div.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.row - div.col-xs-8 + div.col-xs-12.col-sm-12.col-md-12.col-lg-8 div.row - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart(class="{{ avgBlockTime | avgTimeClass }}") //- i.icon-time span.small-title block time //- span.small-value {{ avgBlockTime | avgTimeFilter }} sparkchart.big-details.spark-blocktimes(data="{{lastBlocksTime.join(',')}}", tooltipsuffix="s") - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart.text-info //- i.icon-difficulty span.small-title difficulty //- span.small-value {{ lastDifficulty | number }} sparkchart.big-details.spark-difficulty(data="{{difficultyChart.join(',')}}") - div.col-xs-3.stat-holder.xpull-right + div.col-xs-6.col-sm-4.col-md-3.stat-holder.xpull-right div.big-info.chart.xdouble-chart(class="{{ blockPropagationAvg | propagationAvgTimeClass : true }}") //- i.icon-gas span.small-title block propagation //- span.small-value {{ blockPropagationAvg | blockPropagationFilter : '' }} histogram.big-details.d3-blockpropagation(data="blockPropagationChart") - div.col-xs-3.stat-holder.xpull-right + div.col-xs-6.col-sm-4.col-md-3.stat-holder.xpull-right div.big-info.chart.xdouble-chart span.small-title last blocks miners div.blocks-holder(ng-repeat='miner in miners track by miner.miner', data-toggle="tooltip", data-placement="right", data-original-title="{{miner.blocks}}") @@ -123,7 +123,7 @@ block content minerblock(blocks="{{miner.blocks}}") div.clearfix - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart.text-info //- i.icon-uncle span.small-title uncle count  @@ -131,19 +131,19 @@ block content //- span.small-value {{ bestStats.block.uncles.length }}/{{ uncleCount }} sparkchart.big-details.spark-uncles(data="{{uncleCountChart.join(',')}}") - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart.text-info //- i.icon-uncle span.small-title transactions sparkchart.big-details.spark-transactions(data="{{transactionDensity.join(',')}}") - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart.text-info //- i.icon-gasprice span.small-title gas spending sparkchart.big-details.spark-gasspending(data="{{gasSpending.join(',')}}") - div.col-xs-3.stat-holder + div.col-xs-6.col-sm-4.col-md-3.stat-holder div.big-info.chart.text-info //- i.icon-difficulty span.small-title gas limit @@ -152,7 +152,7 @@ block content - div.col-xs-4.stat-holder.map-holder + div.col-xs-12.col-sm-12.col-md-12.col-lg-4.stat-holder.map-holder //- div.col-xs-12 nodemap#mapHolder(data="map") From 5a92f6cbe32f37ed865f74a9ac652b28a8839757 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 5 Apr 2018 18:22:37 +0900 Subject: [PATCH 22/48] use hidden-* attributes properly --- src/views/index.jade | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/views/index.jade b/src/views/index.jade index 697f6a0..d6e78eb 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -156,7 +156,7 @@ block content //- div.col-xs-12 nodemap#mapHolder(data="map") - div.row + div.row.hidden-xs div.col-xs-12.stats-boxes div.row.second-row div.col-xs-12.stat-holder.box @@ -182,7 +182,7 @@ block content i.icon-check-o(data-toggle="tooltip", data-placement="top", title="Pin nodes to display first", ng-click="orderTable(['-stats.block.number', 'stats.block.propagation'], false)") th.th-nodename i.icon-node(data-toggle="tooltip", data-placement="top", title="Node name", ng-click="orderTable(['info.name'], false)") - th.th-nodetype + th.th-nodetype.hidden-xs i.icon-laptop(data-toggle="tooltip", data-placement="top", title="Node type", ng-click="orderTable(['info.node'], false)") th.th-latency i.icon-clock(data-toggle="tooltip", data-placement="top", title="Node latency", ng-click="orderTable(['stats.latency'], false)") @@ -194,19 +194,19 @@ block content i.icon-network(data-toggle="tooltip", data-placement="top", title="Pending transactions", ng-click="orderTable(['-stats.pending'], false)") th i.icon-block(data-toggle="tooltip", data-placement="top", title="Last block", ng-click="orderTable(['-stats.block.number', 'stats.block.propagation'], false)") - th.th-blockhash   - th.th-blockhash + th.th-blockhash.hidden-xs.hidden-sm.hidden-md   + th.th-blockhash.hidden-xs.hidden-sm.hidden-md i.icon-difficulty(data-toggle="tooltip", data-placement="top", title="Total difficulty", ng-click="orderTable(['-stats.block.totalDifficulty'], false)") th i.icon-check-o(data-toggle="tooltip", data-placement="top", title="Block transactions", ng-click="orderTable(['-stats.block.transactions.length'], false)") - th + th.hidden-xs i.icon-uncle(data-toggle="tooltip", data-placement="top", title="Uncles", ng-click="orderTable(['-stats.block.uncles.length'], false)") th.th-blocktime i.icon-time(data-toggle="tooltip", data-placement="top", title="Last block time", ng-click="orderTable(['-stats.block.received'], false)") th.th-peerPropagationTime i.icon-gas(data-toggle="tooltip", data-placement="top", title="Propagation time", ng-click="orderTable(['-stats.block.number', 'stats.block.propagation'], false)") th.th-peerPropagationChart - th.th-peerPropagationAvg + th.th-peerPropagationAvg.hidden-xs i.icon-gas(data-toggle="tooltip", data-placement="top", title="Average propagation time", ng-click="orderTable(['stats.propagationAvg'], false)") th i.icon-bulb(data-toggle="tooltip", data-placement="top", title="Up-time", ng-click="orderTable(['-stats.uptime'], false)") @@ -219,7 +219,7 @@ block content //- span.small  ({{node.info.ip}}) a.small(href="https://github.com/ethereum/wiki/wiki/Network-Status#updating", target="_blank", data-toggle="tooltip", data-placement="top", data-html="true", data-original-title="Netstats client needs update.
Click this icon for instructions.", class="{{ node.info | nodeClientClass : currentApiVersion }}") i.icon-warning-o - td + td.hidden-xs div.small(ng-bind-html="node.info.node | nodeVersion") td(class="{{ node.readable.latencyClass }}") span.small {{ node.readable.latency }} @@ -230,17 +230,17 @@ block content span(class="{{ node.readable.forkMessage ? node.readable.forkClass : '' }}") {{'#'}}{{ node.stats.block.number | number }} //- a.small(data-toggle="tooltip", data-placement="top", data-html="true", data-original-title="{{ node.readable.forkMessage }}", class="{{ node.readable.forkClass }}") i.icon-warning-o - td(class="{{ node.stats | blockClass : bestBlock }}") + td(class="{{ node.stats | blockClass : bestBlock }}").hidden-xs.hidden-sm.hidden-md span.small {{node.stats.block.hash | hashFilter}} - td(class="{{ node.stats | blockClass : bestBlock }}") + td(class="{{ node.stats | blockClass : bestBlock }}").hidden-xs.hidden-sm.hidden-md span.small {{node.stats.block.totalDifficulty | number}} td(style="padding-left: 14px;") {{node.stats.block.transactions.length || 0}} - td(style="padding-left: 14px;") {{node.stats.block.uncles.length || 0}} + td(style="padding-left: 14px;").hidden-xs {{node.stats.block.uncles.length || 0}} td(class="{{ node.stats.block.received | timeClass : node.stats.active }}") {{node.stats.block.received | blockTimeFilter }} td(class="{{ node.stats | propagationTimeClass : bestBlock }}") div.propagationBox span {{node.stats.block.propagation | blockPropagationFilter}} td.peerPropagationChart(class="{{node.id}}") nodepropagchart(data="{{node.history.join(',')}}") - td(class="{{ node.stats | propagationNodeAvgTimeClass : bestBlock }}") {{ node.stats | blockPropagationAvgFilter : bestBlock }} + td(class="{{ node.stats | propagationNodeAvgTimeClass : bestBlock }}").hidden-xs {{ node.stats | blockPropagationAvgFilter : bestBlock }} td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }} From 838fff5423c7393a95ff6e6628da09a35953bb04 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 5 Apr 2018 18:35:57 +0900 Subject: [PATCH 23/48] simplified *hashrateFilter --- src-lite/js/filters.js | 62 ++++++---------------------- src/js/filters.js | 92 +++++++++--------------------------------- 2 files changed, 32 insertions(+), 122 deletions(-) diff --git a/src-lite/js/filters.js b/src-lite/js/filters.js index c4aaed5..6ab886e 100644 --- a/src-lite/js/filters.js +++ b/src-lite/js/filters.js @@ -38,35 +38,17 @@ angular.module('netStatsApp.filters', []) }) .filter('hashrateFilter', ['$sce', '$filter', function($sce, filter) { return function(hashes, isMining) { - var result = 0; - var unit = 'K'; - if( !isMining ) return $sce.trustAsHtml(''); - if(hashes !== 0 && hashes < 1000) { - result = hashes; - unit = ''; - } - - if(hashes >= 1000 && hashes < Math.pow(1000, 2)) { - result = hashes / 1000; - unit = 'K'; - } - - if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) { - result = hashes / Math.pow(1000, 2); - unit = 'M'; - } - - if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) { - result = hashes / Math.pow(1000, 3); - unit = 'G'; - } + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; + var unit = 'K'; - if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) { - result = hashes / Math.pow(1000, 4); - unit = 'T'; + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; } return $sce.trustAsHtml('' + filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); @@ -273,32 +255,14 @@ angular.module('netStatsApp.filters', []) if(hashes === null) hashes = 0; - var result = 0; + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; var unit = 'K'; - if(hashes !== 0 && hashes < 1000) { - result = hashes; - unit = ''; - } - - if(hashes >= 1000 && hashes < Math.pow(1000, 2)) { - result = hashes / 1000; - unit = 'K'; - } - - if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) { - result = hashes / Math.pow(1000, 2); - unit = 'M'; - } - - if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) { - result = hashes / Math.pow(1000, 3); - unit = 'G'; - } - - if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) { - result = hashes / Math.pow(1000, 4); - unit = 'T'; + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; } if( !isMining ) diff --git a/src/js/filters.js b/src/js/filters.js index 40be828..cfd3eec 100644 --- a/src/js/filters.js +++ b/src/js/filters.js @@ -59,35 +59,17 @@ angular.module('netStatsApp.filters', []) }) .filter('hashrateFilter', ['$sce', '$filter', function($sce, filter) { return function(hashes, isMining) { - var result = 0; - var unit = 'K'; - if( !isMining ) return $sce.trustAsHtml(''); - if(hashes !== 0 && hashes < 1000) { - result = hashes; - unit = ''; - } - - if(hashes >= 1000 && hashes < Math.pow(1000, 2)) { - result = hashes / 1000; - unit = 'K'; - } - - if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) { - result = hashes / Math.pow(1000, 2); - unit = 'M'; - } - - if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) { - result = hashes / Math.pow(1000, 3); - unit = 'G'; - } + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; + var unit = 'K'; - if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) { - result = hashes / Math.pow(1000, 4); - unit = 'T'; + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; } return $sce.trustAsHtml('' + filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); @@ -95,32 +77,14 @@ angular.module('netStatsApp.filters', []) }]) .filter('totalDifficultyFilter', function() { return function(hashes) { - var result = 0; + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; var unit = ''; - if(hashes !== 0 && hashes < 1000) { - result = hashes; - unit = ''; - } - - if(hashes >= 1000 && hashes < Math.pow(1000, 2)) { - result = hashes / 1000; - unit = 'K'; - } - - if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) { - result = hashes / Math.pow(1000, 2); - unit = 'M'; - } - - if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) { - result = hashes / Math.pow(1000, 3); - unit = 'G'; - } - - if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) { - result = hashes / Math.pow(1000, 4); - unit = 'T'; + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; } return result.toFixed(2) + ' ' + unit + 'H'; @@ -327,32 +291,14 @@ angular.module('netStatsApp.filters', []) if(hashes === null) hashes = 0; - var result = 0; + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; var unit = 'K'; - if(hashes !== 0 && hashes < 1000) { - result = hashes; - unit = ''; - } - - if(hashes >= 1000 && hashes < Math.pow(1000, 2)) { - result = hashes / 1000; - unit = 'K'; - } - - if(hashes >= Math.pow(1000, 2) && hashes < Math.pow(1000, 3)) { - result = hashes / Math.pow(1000, 2); - unit = 'M'; - } - - if(hashes >= Math.pow(1000, 3) && hashes < Math.pow(1000, 4)) { - result = hashes / Math.pow(1000, 3); - unit = 'G'; - } - - if(hashes >= Math.pow(1000, 4) && hashes < Math.pow(1000, 5)) { - result = hashes / Math.pow(1000, 4); - unit = 'T'; + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; } if( !isMining ) From 1c551e4a998578ed61d86dd99515b77c1190adfe Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 5 Apr 2018 18:41:32 +0900 Subject: [PATCH 24/48] src-lite: totalDifficultyFilter filter added --- src-lite/js/filters.js | 15 +++++++++++++++ src-lite/views/index.jade | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src-lite/js/filters.js b/src-lite/js/filters.js index 6ab886e..f1d8ced 100644 --- a/src-lite/js/filters.js +++ b/src-lite/js/filters.js @@ -54,6 +54,21 @@ angular.module('netStatsApp.filters', []) return $sce.trustAsHtml('' + filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); }; }]) +.filter('totalDifficultyFilter', function() { + return function(hashes) { + var result = hashes; + var units = ['', 'K', 'M', 'G', 'T', 'P']; + var unit = ''; + + for(var i = 1; result > 1000; i++) + { + result /= 1000; + unit = units[i]; + } + + return result.toFixed(2) + ' ' + unit + 'H'; + }; +}) .filter('nodeVersion', function($sce) { return function(version) { if(typeof version !== 'undefined') diff --git a/src-lite/views/index.jade b/src-lite/views/index.jade index 37276d4..50e7c2f 100644 --- a/src-lite/views/index.jade +++ b/src-lite/views/index.jade @@ -52,7 +52,7 @@ block content div.big-details-holder span.small-title difficulty span.big-details - span.small-hash {{ lastDifficulty | number }} + span.small-hash {{ lastDifficulty | totalDifficultyFilter }} div.clearfix div.clearfix From 9a70697a23f298b9bd4edde124a04bcc78de2370 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 5 Apr 2018 18:48:27 +0900 Subject: [PATCH 25/48] src: remove min-width attribute from body --- src/css/style.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/css/style.css b/src/css/style.css index d887cc9..f8ca299 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -4,7 +4,6 @@ html { body { width: 100%; - min-width: 1900px; font-smooth: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; From 60094ba5ac3b8b919da993912058f1221dc3bbee Mon Sep 17 00:00:00 2001 From: hackyminer Date: Thu, 5 Apr 2018 19:16:42 +0900 Subject: [PATCH 26/48] src: show block counter properly --- src/views/index.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/index.jade b/src/views/index.jade index d6e78eb..b47db46 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -117,9 +117,9 @@ block content div.big-info.chart.xdouble-chart span.small-title last blocks miners div.blocks-holder(ng-repeat='miner in miners track by miner.miner', data-toggle="tooltip", data-placement="right", data-original-title="{{miner.blocks}}") - div.block-count(class="{{miner.blocks | minerBlocksClass : 'text-'}}") {{miner.blocks}} //- div.small-title-miner {{miner.miner | minerNameFilter : miner.name}} div.small-title-miner {{miner.miner}} + div.block-count(class="{{miner.blocks | minerBlocksClass : 'text-'}}") {{miner.blocks}} minerblock(blocks="{{miner.blocks}}") div.clearfix From 3a46bb63958af338df2183f5380c7f0e9ee544de Mon Sep 17 00:00:00 2001 From: hackyminer Date: Sun, 8 Apr 2018 15:22:03 +0900 Subject: [PATCH 27/48] remove google analytics --- src-lite/js/script.js | 8 -------- src/js/script.js | 9 --------- 2 files changed, 17 deletions(-) diff --git a/src-lite/js/script.js b/src-lite/js/script.js index 73343b6..ff0ccf5 100644 --- a/src-lite/js/script.js +++ b/src-lite/js/script.js @@ -26,11 +26,3 @@ moment.relativeTimeThreshold('M', 12); })(); - -(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ -(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), -m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) -})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - -ga('create', 'UA-63657296-1', 'auto'); -ga('send', 'pageview'); \ No newline at end of file diff --git a/src/js/script.js b/src/js/script.js index 1881020..469b20f 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -26,12 +26,3 @@ moment.relativeTimeThreshold('M', 12); })(); - -(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ -(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), -m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) -})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - -// ga('create', 'UA-68390837-2', 'auto'); -ga('create', 'UA-80834434-1', 'auto'); -ga('send', 'pageview'); \ No newline at end of file From 815f62f3a87d65fe6b87c3e6e3d3524c87bbd6da Mon Sep 17 00:00:00 2001 From: hackyminer Date: Sun, 8 Apr 2018 20:39:22 +0900 Subject: [PATCH 28/48] fixed layout and css/js for responsive layout. --- src/css/style.css | 56 ++++++++++++++++++++++++++++++++++++++--- src/js/directives.js | 59 ++++++++++++++++++++++++++++++++++++++++++-- src/js/script.js | 5 ++++ src/views/index.jade | 27 +++++++++++--------- 4 files changed, 130 insertions(+), 17 deletions(-) diff --git a/src/css/style.css b/src/css/style.css index f8ca299..47b5649 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -147,9 +147,9 @@ span.small-title span.small { } .big-info.chart .big-details { - display: block; - position: absolute; + display: table; top: 40px; + margin: 0 auto; } .big-info.chart { @@ -166,6 +166,8 @@ span.small-title span.small { width: 288px; padding-top: 6px; margin-left: -2px; + display: table; + margin: 0 auto; } .blocks-holder { @@ -465,4 +467,52 @@ svg .axis text { svg .y.axis .tick:first-child text { opacity: 0; -} \ No newline at end of file +} + +@media (max-width: 768px) { + .container-fluid { + padding-left: 5px; + padding-right: 5px; + } + + .big-info .icon-full-width i { + width: 75px; + height: 67px; + font-size: 67px; + margin-left: -25px; + } + + .big-info .big-details-holder { + left: 75px; + } + + .big-info .big-details { + font-size: 35px; + } + + .blocks-holder div.small-title-miner { + font-family: inherit; + font-size: 11px; + letter-spacing: -.5px; + } + + .blocks-holder { + width: 100%; + } + + .big-info.chart i, .second-row .box i { + font-size: 18px; + margin-right: 0px; + } + + .second-row .box { + height: 100%; /* BUG XXX */ + } +} + + +@media (max-width: 600px) { + .blocks-holder div.small-title-miner { + font-size: 10px; + } +} diff --git a/src/js/directives.js b/src/js/directives.js index b71c62b..19bb3ec 100644 --- a/src/js/directives.js +++ b/src/js/directives.js @@ -100,6 +100,24 @@ angular.module('netStatsApp.directives', []) { tElement.replaceWith('' + tAttrs.data + ""); + // register resize watcher + var timeout; + var width; + $(window).on('resize', function(e) { + if( $('body').width() < 600 ) + width = 4; + else if( $('body').width() < 1200 ) + width = 5; + else + width = 6; + + if(timeout) + clearTimeout(timeout); + timeout = setTimeout(function() { + $.fn.sparkline.defaults.bar.barWidth = width; + }, 200); + }); + return function(scope, element, attrs) { attrs.$observe("data", function (newValue) @@ -302,6 +320,12 @@ angular.module('netStatsApp.directives', []) var width = 280 - margin.left - margin.right, height = 63 - margin.top - margin.bottom; + // fix for mobile devices + if( $('body').width() < 600 ) + width = 200 - margin.left - margin.right; + else( $('body').width() < 1200 ) + width = 240 - margin.left - margin.right; + var TICKS = 40; var x = d3.scale.linear() @@ -342,10 +366,26 @@ angular.module('netStatsApp.directives', []) return '
' + (d.x/1000) + 's - ' + ((d.x + d.dx)/1000) + 's
Percent: ' + Math.round(d.y * 100) + '%' + '
Frequency: ' + d.frequency + '
Cumulative: ' + Math.round(d.cumpercent*100) + '%
'; }) - scope.init = function() + scope.init = function(width) { var data = scope.data; + var x = d3.scale.linear() + .domain([0, 10000]) + .rangeRound([0, width]) + .interpolate(d3.interpolateRound); + + var xAxis = d3.svg.axis() + .scale(x) + .orient("bottom") + .ticks(4, ",.1s") + .tickFormat(function(t){ return t/1000 + "s"}); + + var line = d3.svg.line() + .x(function(d) { return x(d.x + d.dx/2) - 1; }) + .y(function(d) { return y(d.y) - 2; }) + .interpolate('basis'); + // Adjust y axis y.domain([0, d3.max(data, function(d) { return d.y; })]); @@ -414,9 +454,24 @@ angular.module('netStatsApp.directives', []) scope.$watch('data', function() { if(scope.data.length > 0) { - scope.init(); + scope.init(width); } }, true); + + var timeout; + $(window).on('resize', function(e) { + var width = 280 - margin.left - margin.right; + if( $('body').width() < 768 ) + width = 200 - margin.left - margin.right; + + if(timeout) + clearTimeout(timeout); + + timeout = setTimeout(function() { + // redraw + scope.init(width); + }, 200); + }); } }; }]); \ No newline at end of file diff --git a/src/js/script.js b/src/js/script.js index 469b20f..ff9157f 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -7,6 +7,11 @@ $.fn.sparkline.defaults.bar.height = 63; $.fn.sparkline.defaults.bar.barWidth = 6; + + if( $('body').width() < 600 ) + $.fn.sparkline.defaults.bar.barWidth = 4; + else if( $('body').width() < 1200 ) + $.fn.sparkline.defaults.bar.barWidth = 5; $.fn.sparkline.defaults.bar.barSpacing = 1; $.fn.sparkline.defaults.bar.tooltipClassname = 'jqstooltip'; $.fn.sparkline.defaults.bar.tooltipOffsetX = 0; diff --git a/src/views/index.jade b/src/views/index.jade index b47db46..6c02255 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -18,7 +18,7 @@ block content i.icon-uncle div.big-details-holder span.small-title uncles  - span.small (current / last 50) + span.small.hidden-xs (current / last 50) span.big-details {{ bestStats.block.uncles.length }}/{{ uncleCount }} div.clearfix div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder @@ -43,7 +43,10 @@ block content div.pull-left.icon-full-width i.icon-hashrate div.big-details-holder - span.small-title avg network hashrate + span.small-title + span.hidden-xs avg  + | network hash + span.hidden-xs rate span.big-details(ng-bind-html="avgHashrate | networkHashrateFilter") div.clearfix div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder @@ -87,7 +90,7 @@ block content i.icon-bulb span.small-title uptime span.small-value {{ upTimeTotal | upTimeFilter }} - div.col-sm-6.col-md-6.col-lg-2.stat-holder.box + div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.row div.col-xs-12.col-sm-12.col-md-12.col-lg-8 @@ -127,7 +130,7 @@ block content div.big-info.chart.text-info //- i.icon-uncle span.small-title uncle count  - span.small (25 blocks per bar) + span.small.hidden-xs (25 blocks per bar) //- span.small-value {{ bestStats.block.uncles.length }}/{{ uncleCount }} sparkchart.big-details.spark-uncles(data="{{uncleCountChart.join(',')}}") @@ -184,20 +187,20 @@ block content i.icon-node(data-toggle="tooltip", data-placement="top", title="Node name", ng-click="orderTable(['info.name'], false)") th.th-nodetype.hidden-xs i.icon-laptop(data-toggle="tooltip", data-placement="top", title="Node type", ng-click="orderTable(['info.node'], false)") - th.th-latency + th.th-latency.hidden-xs i.icon-clock(data-toggle="tooltip", data-placement="top", title="Node latency", ng-click="orderTable(['stats.latency'], false)") - th + th.hidden-xs i.icon-mining(data-toggle="tooltip", data-placement="top", title="Is mining", ng-click="orderTable(['-stats.hashrate'], false)") th i.icon-group(data-toggle="tooltip", data-placement="top", title="Peers", ng-click="orderTable(['-stats.peers'], false)") th i.icon-network(data-toggle="tooltip", data-placement="top", title="Pending transactions", ng-click="orderTable(['-stats.pending'], false)") - th + th.hidden-xs i.icon-block(data-toggle="tooltip", data-placement="top", title="Last block", ng-click="orderTable(['-stats.block.number', 'stats.block.propagation'], false)") th.th-blockhash.hidden-xs.hidden-sm.hidden-md   th.th-blockhash.hidden-xs.hidden-sm.hidden-md i.icon-difficulty(data-toggle="tooltip", data-placement="top", title="Total difficulty", ng-click="orderTable(['-stats.block.totalDifficulty'], false)") - th + th.hidden-xs i.icon-check-o(data-toggle="tooltip", data-placement="top", title="Block transactions", ng-click="orderTable(['-stats.block.transactions.length'], false)") th.hidden-xs i.icon-uncle(data-toggle="tooltip", data-placement="top", title="Uncles", ng-click="orderTable(['-stats.block.uncles.length'], false)") @@ -221,12 +224,12 @@ block content i.icon-warning-o td.hidden-xs div.small(ng-bind-html="node.info.node | nodeVersion") - td(class="{{ node.readable.latencyClass }}") + td(class="{{ node.readable.latencyClass }}").hidden-xs span.small {{ node.readable.latency }} - td(class="{{ node.stats.mining | hashrateClass : node.stats.active }}", ng-bind-html="node.stats.hashrate | hashrateFilter : node.stats.mining") + td(class="{{ node.stats.mining | hashrateClass : node.stats.active }}", ng-bind-html="node.stats.hashrate | hashrateFilter : node.stats.mining").hidden-xs td(class="{{ node.stats.peers | peerClass : node.stats.active }}", style="padding-left: 11px;") {{node.stats.peers}} td(style="padding-left: 15px;") {{node.stats.pending}} - td(class="{{ node.stats | blockClass : bestBlock }}") + td(class="{{ node.stats | blockClass : bestBlock }}").hidden-xs span(class="{{ node.readable.forkMessage ? node.readable.forkClass : '' }}") {{'#'}}{{ node.stats.block.number | number }} //- a.small(data-toggle="tooltip", data-placement="top", data-html="true", data-original-title="{{ node.readable.forkMessage }}", class="{{ node.readable.forkClass }}") i.icon-warning-o @@ -234,7 +237,7 @@ block content span.small {{node.stats.block.hash | hashFilter}} td(class="{{ node.stats | blockClass : bestBlock }}").hidden-xs.hidden-sm.hidden-md span.small {{node.stats.block.totalDifficulty | number}} - td(style="padding-left: 14px;") {{node.stats.block.transactions.length || 0}} + td(style="padding-left: 14px;").hidden-xs {{node.stats.block.transactions.length || 0}} td(style="padding-left: 14px;").hidden-xs {{node.stats.block.uncles.length || 0}} td(class="{{ node.stats.block.received | timeClass : node.stats.active }}") {{node.stats.block.received | blockTimeFilter }} td(class="{{ node.stats | propagationTimeClass : bestBlock }}") From 5f786d8a2b050b09feb6d7b1e5fbff8405617f90 Mon Sep 17 00:00:00 2001 From: hackyminer Date: Mon, 25 Jun 2018 09:29:34 +0900 Subject: [PATCH 29/48] fixed totalDifficultyFilter, fixed gaslimit number format --- src/js/filters.js | 6 +++--- src/views/index.jade | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/js/filters.js b/src/js/filters.js index cfd3eec..c8947e1 100644 --- a/src/js/filters.js +++ b/src/js/filters.js @@ -75,7 +75,7 @@ angular.module('netStatsApp.filters', []) return $sce.trustAsHtml('' + filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); }; }]) -.filter('totalDifficultyFilter', function() { +.filter('totalDifficultyFilter', ['$sce', '$filter', function($sce, filter) { return function(hashes) { var result = hashes; var units = ['', 'K', 'M', 'G', 'T', 'P']; @@ -87,9 +87,9 @@ angular.module('netStatsApp.filters', []) unit = units[i]; } - return result.toFixed(2) + ' ' + unit + 'H'; + return $sce.trustAsHtml(filter('number')(result.toFixed(2)) + ' ' + unit + 'H'); }; -}) +}]) .filter('nodeVersion', function($sce) { return function(version) { if(version) diff --git a/src/views/index.jade b/src/views/index.jade index 6c02255..59579e0 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -55,8 +55,7 @@ block content i.icon-difficulty div.big-details-holder span.small-title difficulty - span.big-details - span.small-hash {{ lastDifficulty | totalDifficultyFilter }} + span.big-details(ng-bind-html="lastDifficulty | totalDifficultyFilter") div.clearfix div.clearfix @@ -79,7 +78,7 @@ block content div.gasprice.text-info i.icon-gasprice span.small-title gas limit - span.small-value {{ bestStats.block.gasLimit }} gas + span.small-value {{ bestStats.block.gasLimit | number }} gas div.col-xs-6.col-sm-6.col-md-6.col-lg-2.stat-holder.box div.page-latency(class="{{ {active: true, latency: latency} | latencyClass }}") i.icon-clock From a3df0542ba8f58c435bd0406c7ffeb76365e131d Mon Sep 17 00:00:00 2001 From: EOS Classic Date: Sun, 16 Sep 2018 01:15:18 +0900 Subject: [PATCH 30/48] Comment warning message --- src/views/index.jade | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/views/index.jade b/src/views/index.jade index 59579e0..1af92c8 100644 --- a/src/views/index.jade +++ b/src/views/index.jade @@ -161,11 +161,11 @@ block content div.row.hidden-xs div.col-xs-12.stats-boxes div.row.second-row - div.col-xs-12.stat-holder.box - div.active-nodes.text-warning - i.icon-warning-o - span.small-title ATTENTION! - span.small-value This page does not represent the entire state of the ethereum network - listing a node on this page is a voluntary process. + //- div.col-xs-12.stat-holder.box + //- div.active-nodes.text-warning + //- i.icon-warning-o + //- span.small-title ATTENTION! + //- span.small-value This page does not represent the entire state of the ethereum network - listing a node on this page is a voluntary process. //- div.col-xs-12.stat-holder.box //- div.active-nodes.text-danger //- i.icon-hashrate From 7c5fe12fc84a26ce5517279ecc5e4864ef7a101b Mon Sep 17 00:00:00 2001 From: EOS Classic Date: Sun, 16 Sep 2018 01:16:10 +0900 Subject: [PATCH 31/48] Add package-lock.json --- package-lock.json | 2287 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2287 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3302f43 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2287 @@ +{ + "name": "eth-netstats", + "version": "0.0.9", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", + "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", + "requires": { + "mime-types": "~2.1.6", + "negotiator": "0.5.3" + } + }, + "access-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/access-control/-/access-control-1.0.1.tgz", + "integrity": "sha512-H5aqjkogmFxfaOrfn/e42vyspHVXuJ8er63KuljJXpOyJ1ZO/U5CrHfO8BLKIy2w7mBM02L5quL0vbfQqrGQbA==", + "requires": { + "millisecond": "~0.1.2", + "setheader": "~1.0.0", + "vary": "~1.1.0" + }, + "dependencies": { + "setheader": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/setheader/-/setheader-1.0.1.tgz", + "integrity": "sha512-iNDik8ipRBZHfpbpdWlhfZxc0JM9Cg4NYo8jqBkjSRLPxvcgnrE9oiF3AhpFvypg2erVyWNS+QhykhQt0G9tpA==", + "requires": { + "diagnostics": "1.x.x" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } + }, + "acorn": { + "version": "2.7.0", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + }, + "acorn-globals": { + "version": "1.0.9", + "resolved": "http://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "requires": { + "acorn": "^2.1.0" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "requires": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" + }, + "dependencies": { + "underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=" + } + } + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", + "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + } + } + }, + "asyncemit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/asyncemit/-/asyncemit-3.0.1.tgz", + "integrity": "sha1-zD4P4No5tTzBXls6qGFupqcr1Zk=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "body-parser": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", + "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", + "requires": { + "bytes": "2.1.0", + "content-type": "~1.0.1", + "debug": "~2.2.0", + "depd": "~1.0.1", + "http-errors": "~1.3.1", + "iconv-lite": "0.4.11", + "on-finished": "~2.3.0", + "qs": "4.0.0", + "raw-body": "~2.1.2", + "type-is": "~1.6.6" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "requires": { + "pako": "~0.2.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", + "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=" + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "1.1.1", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", + "integrity": "sha1-UJr7ZwZudJn36zU1x3RFdyri0Bk=", + "requires": { + "ansi-styles": "^2.1.0", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "character-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", + "integrity": "sha1-wN3kqxgnE7kZuXCVmhI+zBow/NY=" + }, + "clean-css": { + "version": "3.4.28", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz", + "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=", + "requires": { + "commander": "2.8.x", + "source-map": "0.4.x" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + } + } + }, + "coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=" + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, + "colors": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", + "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==" + }, + "colorspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", + "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connected": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/connected/-/connected-0.0.2.tgz", + "integrity": "sha1-e1dVshbOMf+rzMOOn04d/Bw7fG0=" + }, + "constantinople": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", + "integrity": "sha1-S5RdmTeQe82Y7ldRIsOBdRZUQUE=", + "requires": { + "acorn": "^2.1.0" + } + }, + "content-disposition": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", + "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", + "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-server": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/create-server/-/create-server-1.0.1.tgz", + "integrity": "sha1-FkNCg08Yi77Hx7xGZ0Y8wrEwTEQ=", + "requires": { + "connected": "0.0.x" + } + }, + "css": { + "version": "1.0.8", + "resolved": "http://registry.npmjs.org/css/-/css-1.0.8.tgz", + "integrity": "sha1-k4aBHKgrzMnuf7WnMrHioxfIo+c=", + "requires": { + "css-parse": "1.0.4", + "css-stringify": "1.0.5" + } + }, + "css-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", + "integrity": "sha1-OLBQP7+dqfVOnB29pg4UXHcRe90=" + }, + "css-stringify": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", + "integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE=" + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "d3": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.6.tgz", + "integrity": "sha1-lFHGUcpzP7lnLIH7fyZVFkpzpC0=" + }, + "dateformat": { + "version": "1.0.2-1.2.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", + "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=" + }, + "debug": { + "version": "2.2.0", + "resolved": "http://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "depd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" + }, + "destroy": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", + "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" + }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz", + "integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=" + }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" + } + }, + "env-variable": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.4.tgz", + "integrity": "sha512-+jpGxSWG4vr6gVxUHOc4p+ilPnql7NzZxOZBxNldsKGjCF+97df3CbuX7XMaDa5oAVkKQj4rKp38rYdC4VcpDg==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-html": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz", + "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "etag": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=" + }, + "event-stream": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz", + "integrity": "sha512-dGXNg4F/FgVzlApjzItL+7naHutA3fDqbV/zAZqDDlXTjiMnQmZKu+prImWKszeBM5UQeGvAl3u1wBiKeDh61g==", + "requires": { + "duplexer": "^0.1.1", + "flatmap-stream": "^0.1.0", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "http://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + }, + "eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "express": { + "version": "4.13.3", + "resolved": "http://registry.npmjs.org/express/-/express-4.13.3.tgz", + "integrity": "sha1-3bLx+0UCvzNZjSsDKwN5YMpsgKM=", + "requires": { + "accepts": "~1.2.12", + "array-flatten": "1.1.1", + "content-disposition": "0.5.0", + "content-type": "~1.0.1", + "cookie": "0.1.3", + "cookie-signature": "1.0.6", + "debug": "~2.2.0", + "depd": "~1.0.1", + "escape-html": "1.0.2", + "etag": "~1.7.0", + "finalhandler": "0.4.0", + "fresh": "0.3.0", + "merge-descriptors": "1.0.0", + "methods": "~1.1.1", + "on-finished": "~2.3.0", + "parseurl": "~1.3.0", + "path-to-regexp": "0.1.7", + "proxy-addr": "~1.0.8", + "qs": "4.0.0", + "range-parser": "~1.0.2", + "send": "0.13.0", + "serve-static": "~1.10.0", + "type-is": "~1.6.6", + "utils-merge": "1.0.0", + "vary": "~1.0.1" + } + }, + "extendible": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/extendible/-/extendible-0.1.1.tgz", + "integrity": "sha1-4qN+2HEp+0+VM+io11BiMKU5yQU=" + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "file-sync-cmp": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", + "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=" + }, + "finalhandler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", + "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", + "requires": { + "debug": "~2.2.0", + "escape-html": "1.0.2", + "on-finished": "~2.3.0", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", + "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "requires": { + "glob": "~3.2.9", + "lodash": "~2.4.1" + }, + "dependencies": { + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "requires": { + "inherits": "2", + "minimatch": "0.3" + } + }, + "lodash": { + "version": "2.4.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } + } + }, + "flatmap-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.0.tgz", + "integrity": "sha512-Nlic4ZRYxikqnK5rj3YoxDVKGGtUjcNDUtvQ7XsdGLZmMwdUYnXf10o1zcXtzEZTBgc6GxeRpQxV/Wu3WPIIHA==" + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "forwarded-for": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/forwarded-for/-/forwarded-for-1.0.1.tgz", + "integrity": "sha1-59pIFAJRaP/AoQ0/954UFfRq9Gk=" + }, + "fresh": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=" + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fusing": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fusing/-/fusing-1.0.0.tgz", + "integrity": "sha1-VQwV12r5Jld4qgUezkTUAAoJjUU=", + "requires": { + "emits": "3.0.x", + "predefine": "0.1.x" + } + }, + "geoip-lite": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/geoip-lite/-/geoip-lite-1.3.2.tgz", + "integrity": "sha512-UHg8AsRqqc5vRmQTOzhhv4v4TS1e+zogrGUcP4JAb8uymhN8UvmpRfOBaFsFcJlZm+chTxuGM/k0TNALesmObg==", + "requires": { + "async": "^2.1.1", + "colors": "^1.1.2", + "glob": "^7.1.1", + "iconv-lite": "^0.4.13", + "ip-address": "^5.8.9", + "lazy": "^1.0.11", + "rimraf": "^2.5.2", + "save": "^2.3.2", + "yauzl": "^2.9.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=" + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "grunt": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", + "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "requires": { + "async": "~0.1.22", + "coffee-script": "~1.3.3", + "colors": "~0.6.2", + "dateformat": "1.0.2-1.2.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.1.2", + "getobject": "~0.1.0", + "glob": "~3.1.21", + "grunt-legacy-log": "~0.1.0", + "grunt-legacy-util": "~0.2.0", + "hooker": "~0.2.3", + "iconv-lite": "~0.2.11", + "js-yaml": "~2.0.5", + "lodash": "~0.9.2", + "minimatch": "~0.2.12", + "nopt": "~1.0.10", + "rimraf": "~2.2.8", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + }, + "dependencies": { + "async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "requires": { + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" + } + }, + "iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=" + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=" + }, + "lodash": { + "version": "0.9.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=" + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "rimraf": { + "version": "2.2.8", + "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + } + } + }, + "grunt-contrib-clean": { + "version": "0.6.0", + "resolved": "http://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", + "integrity": "sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY=", + "requires": { + "rimraf": "~2.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + } + } + }, + "grunt-contrib-concat": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-concat/-/grunt-contrib-concat-0.5.1.tgz", + "integrity": "sha1-lTxu/f39LBB6uchQd/LUsk0xzUk=", + "requires": { + "chalk": "^0.5.1", + "source-map": "^0.3.0" + }, + "dependencies": { + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" + }, + "chalk": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "requires": { + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" + } + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "requires": { + "ansi-regex": "^0.2.0" + } + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "requires": { + "ansi-regex": "^0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" + } + } + }, + "grunt-contrib-copy": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.8.2.tgz", + "integrity": "sha1-3zHJD/zECbyfr+ROwN0eQlmRb+o=", + "requires": { + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + } + }, + "grunt-contrib-cssmin": { + "version": "0.12.3", + "resolved": "http://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-0.12.3.tgz", + "integrity": "sha1-QVdZYJb7dlb8RktMx7B0beHzkBQ=", + "requires": { + "chalk": "^1.0.0", + "clean-css": "^3.1.0", + "maxmin": "^1.1.0" + } + }, + "grunt-contrib-jade": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-jade/-/grunt-contrib-jade-0.14.1.tgz", + "integrity": "sha1-5nkmZdsC2kFti6ZmhAGjihaxYl0=", + "requires": { + "chalk": "~0.5.1", + "jade": "~1.9.1" + }, + "dependencies": { + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=" + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=" + }, + "chalk": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "requires": { + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" + } + }, + "commander": { + "version": "2.6.0", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "requires": { + "ansi-regex": "^0.2.0" + } + }, + "jade": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.9.2.tgz", + "integrity": "sha1-C4n5xg1OrSc46Ca6eyzKyaVwKr4=", + "requires": { + "character-parser": "1.2.1", + "commander": "~2.6.0", + "constantinople": "~3.0.1", + "mkdirp": "~0.5.0", + "transformers": "2.1.0", + "void-elements": "~2.0.1", + "with": "~4.0.0" + } + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "requires": { + "ansi-regex": "^0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=" + } + } + }, + "grunt-contrib-uglify": { + "version": "0.9.2", + "resolved": "http://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.9.2.tgz", + "integrity": "sha1-GmHG8hJBDkq7T3yJFTcXsQFWAmA=", + "requires": { + "chalk": "^1.0.0", + "lodash": "^3.2.0", + "maxmin": "^1.0.0", + "uglify-js": "^2.4.24", + "uri-path": "0.0.2" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + } + } + } + }, + "grunt-legacy-log": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", + "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "requires": { + "colors": "~0.6.2", + "grunt-legacy-log-utils": "~0.1.1", + "hooker": "~0.2.3", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "lodash": { + "version": "2.4.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=" + } + } + }, + "grunt-legacy-log-utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", + "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "requires": { + "colors": "~0.6.2", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "dependencies": { + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "lodash": { + "version": "2.4.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=" + } + } + }, + "grunt-legacy-util": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", + "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "requires": { + "async": "~0.1.22", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~0.9.2", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + }, + "dependencies": { + "async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=" + }, + "lodash": { + "version": "0.9.2", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=" + } + } + }, + "gzip-size": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz", + "integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=", + "requires": { + "browserify-zlib": "^0.1.4", + "concat-stream": "^1.4.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=" + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==" + }, + "http-errors": { + "version": "1.3.1", + "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", + "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", + "requires": { + "inherits": "~2.0.1", + "statuses": "1" + } + }, + "iconv-lite": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", + "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ip-address": { + "version": "5.8.9", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-5.8.9.tgz", + "integrity": "sha512-7ay355oMN34iXhET1BmCJVsHjOTSItEEIIpOs38qUC23AIhOy+xIPnkrTuEFjeLMrTJ7m8KMXWgWfy/2Vn9sDw==", + "requires": { + "jsbn": "1.1.0", + "lodash.find": "^4.6.0", + "lodash.max": "^4.0.1", + "lodash.merge": "^4.6.0", + "lodash.padstart": "^4.6.1", + "lodash.repeat": "^4.1.0", + "sprintf-js": "1.1.0" + } + }, + "ipaddr.js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", + "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jade": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", + "integrity": "sha1-nIDlOMEtP7lcjZu5VZ+gzAQEBf0=", + "requires": { + "character-parser": "1.2.1", + "clean-css": "^3.1.9", + "commander": "~2.6.0", + "constantinople": "~3.0.1", + "jstransformer": "0.0.2", + "mkdirp": "~0.5.0", + "transformers": "2.1.0", + "uglify-js": "^2.4.19", + "void-elements": "~2.0.1", + "with": "~4.0.0" + }, + "dependencies": { + "commander": { + "version": "2.6.0", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + } + } + } + }, + "js-yaml": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", + "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "requires": { + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" + } + }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha1-sBMHyym2GKHtJux56RH4A8TaAEA=" + }, + "jstransformer": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", + "integrity": "sha1-eq4pqQPRls+glz2IXT5HlH7Ndqs=", + "requires": { + "is-promise": "^2.0.0", + "promise": "^6.0.1" + }, + "dependencies": { + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "promise": { + "version": "6.1.0", + "resolved": "http://registry.npmjs.org/promise/-/promise-6.1.0.tgz", + "integrity": "sha1-LOcp9rlLRcJoka0GAsXJDgTG7vY=", + "requires": { + "asap": "~1.0.0" + } + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "kuler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.0.tgz", + "integrity": "sha512-oyy6pu/yWRjiVfCoJebNUKFL061sNtrs9ejKTbirIwY3oiHmENVCSkHhxDV85Dkm7JYR/czMCBeoM87WilTdSg==", + "requires": { + "colornames": "^1.1.1" + } + }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + } + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, + "lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=" + }, + "lodash.max": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.max/-/lodash.max-4.0.1.tgz", + "integrity": "sha1-hzVWbGGLNan3YFILSHrnllivE2o=" + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=" + }, + "lodash.repeat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-4.1.0.tgz", + "integrity": "sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ=" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=" + }, + "maxmin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "requires": { + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^1.0.0", + "pretty-bytes": "^1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz", + "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "millisecond": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz", + "integrity": "sha1-bMWtOGJByrjniv+WT4cCjuyS2sU=" + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + }, + "mime-types": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "requires": { + "mime-db": "~1.36.0" + } + }, + "mingo": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/mingo/-/mingo-1.3.3.tgz", + "integrity": "sha1-aSLE0Ufvx3GgFCWixMj3eER4xUY=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "negotiator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", + "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=" + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "requires": { + "wordwrap": "~0.0.2" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + } + } + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "~2.3" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "predefine": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/predefine/-/predefine-0.1.2.tgz", + "integrity": "sha1-KqkrRJa8H4VU5DpF92v75Q0z038=", + "requires": { + "extendible": "0.1.x" + } + }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, + "primus": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/primus/-/primus-6.1.0.tgz", + "integrity": "sha1-s79Mk46weHS4crwrDOnA2oVdbBI=", + "requires": { + "access-control": "~1.0.0", + "asyncemit": "~3.0.1", + "create-server": "~1.0.1", + "diagnostics": "~1.1.0", + "eventemitter3": "~2.0.2", + "forwarded-for": "~1.0.1", + "fusing": "~1.0.0", + "setheader": "~0.0.4", + "ultron": "~1.1.0", + "yeast": "~0.1.2" + } + }, + "primus-emit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/primus-emit/-/primus-emit-1.0.0.tgz", + "integrity": "sha1-5LIxaHBsvqfLpjC0goBtv/30w+k=" + }, + "primus-spark-latency": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/primus-spark-latency/-/primus-spark-latency-0.1.1.tgz", + "integrity": "sha1-Mo04R2esLUriKvBr3SWwx4U9KZE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "promise": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/promise/-/promise-2.0.0.tgz", + "integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=", + "requires": { + "is-promise": "~1" + } + }, + "proxy-addr": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", + "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", + "requires": { + "forwarded": "~0.1.0", + "ipaddr.js": "1.0.5" + } + }, + "qs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", + "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" + }, + "range-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", + "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" + }, + "raw-body": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", + "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", + "requires": { + "bytes": "2.4.0", + "iconv-lite": "0.4.13", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "save": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/save/-/save-2.3.2.tgz", + "integrity": "sha1-hZJnS1VlzE4SvG3dnLCfgo4+z30=", + "requires": { + "async": "^2.4.1", + "event-stream": "^3.3.4", + "lodash.assign": "^4.2.0", + "mingo": "^1.3.1" + } + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" + }, + "send": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz", + "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=", + "requires": { + "debug": "~2.2.0", + "depd": "~1.0.1", + "destroy": "1.0.3", + "escape-html": "1.0.2", + "etag": "~1.7.0", + "fresh": "0.3.0", + "http-errors": "~1.3.1", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "~2.3.0", + "range-parser": "~1.0.2", + "statuses": "~1.2.1" + }, + "dependencies": { + "statuses": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", + "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" + } + } + }, + "serve-static": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", + "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", + "requires": { + "escape-html": "~1.0.3", + "parseurl": "~1.3.1", + "send": "0.13.2" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "send": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", + "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", + "requires": { + "debug": "~2.2.0", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "escape-html": "~1.0.3", + "etag": "~1.7.0", + "fresh": "0.3.0", + "http-errors": "~1.3.1", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "~2.3.0", + "range-parser": "~1.0.3", + "statuses": "~1.2.1" + } + }, + "statuses": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", + "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" + } + } + }, + "setheader": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/setheader/-/setheader-0.0.4.tgz", + "integrity": "sha1-km7SjPdiFJYgkx566j8blYFuxpQ=", + "requires": { + "debug": "0.7.x" + }, + "dependencies": { + "debug": { + "version": "0.7.4", + "resolved": "http://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + } + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "source-map": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.3.0.tgz", + "integrity": "sha1-hYb7mloAXltQHiHNGLbyG0V60fk=", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", + "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==" + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "sprintf-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.0.tgz", + "integrity": "sha1-z/yvcC2vZeo5u04PorKZzsGhvkY=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "through": { + "version": "2.3.8", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "transformers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", + "integrity": "sha1-XSPLNVYd2F3Gf7hIIwm0fVPM6ac=", + "requires": { + "css": "~1.0.8", + "promise": "~2.0", + "uglify-js": "~2.2.5" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "2.2.5", + "resolved": "http://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", + "integrity": "sha1-puAqcNg5eSuXgEiLe4sYTAlcmcc=", + "requires": { + "optimist": "~0.3.5", + "source-map": "~0.1.7" + }, + "dependencies": { + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + }, + "underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-path": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-0.0.2.tgz", + "integrity": "sha1-gD6wHy/rF5J9zOD2GH5yt19T9VQ=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", + "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=" + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + }, + "which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=" + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "with": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", + "integrity": "sha1-7v0VTp550sjTQXtkeo8U2f7M4U4=", + "requires": { + "acorn": "^1.0.1", + "acorn-globals": "^1.0.3" + }, + "dependencies": { + "acorn": { + "version": "1.2.2", + "resolved": "http://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=" + } + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + }, + "dependencies": { + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + } + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + } + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} From e4bd94e56aa2919e70a6d89bfda3860ada3358ae Mon Sep 17 00:00:00 2001 From: EOS Classic Date: Sun, 16 Sep 2018 01:42:52 +0900 Subject: [PATCH 32/48] Remove un-maintained files --- src-lite/css/animation.css | 85 - src-lite/css/bootstrap.min.css | 10 - src-lite/css/minimal-icons-codes.css | 23 - src-lite/css/minimal-icons-embedded.css | 76 - src-lite/css/minimal-icons-ie7-codes.css | 23 - src-lite/css/minimal-icons-ie7.css | 34 - src-lite/css/minimal-icons.css | 78 - src-lite/css/style.css | 468 - src-lite/css/toastr.min.css | 1 - src-lite/fonts/Simple-Line-Icons.ttf | Bin 35304 -> 0 bytes src-lite/fonts/minimal-icons.eot | Bin 10972 -> 0 bytes src-lite/fonts/minimal-icons.svg | 33 - src-lite/fonts/minimal-icons.ttf | Bin 10784 -> 0 bytes src-lite/fonts/minimal-icons.woff | Bin 7008 -> 0 bytes src-lite/images/favicon.ico | Bin 574 -> 0 bytes src-lite/images/favicon.png | Bin 574 -> 0 bytes src-lite/js/app.js | 40 - src-lite/js/controllers.js | 562 - src-lite/js/directives.js | 8 - src-lite/js/filters.js | 596 - src-lite/js/lib/angular.js | 22154 ---------------- src-lite/js/lib/angular.min.js | 217 - src-lite/js/lib/angular.min.js.map | 8 - src-lite/js/lib/bootstrap.min.js | 12 - src-lite/js/lib/d3.js | 9504 ------- src-lite/js/lib/d3.min.js | 5 - src-lite/js/lib/d3.tip.min.js | 1 - src-lite/js/lib/jquery-1.11.3.js | 10351 -------- src-lite/js/lib/jquery-1.11.3.min.js | 6 - src-lite/js/lib/jquery-1.11.3.min.js.map | 1 - src-lite/js/lib/jquery.sparkline.js | 3054 --- src-lite/js/lib/jquery.sparkline.min.js | 5 - src-lite/js/lib/lodash.js | 12397 --------- src-lite/js/lib/lodash.min.js | 101 - src-lite/js/lib/moment.en.min.js | 1 - src-lite/js/lib/moment.js | 3111 --- src-lite/js/lib/moment.min.js | 7 - src-lite/js/lib/primus.min.js | 1 - src-lite/js/lib/toastr.min.js | 1 - src-lite/js/script.js | 28 - src-lite/views/index.jade | 133 - src-lite/views/layout.jade | 13 - web-app/.meteor/local/build/README | 14 - web-app/.meteor/local/build/main.js | 9 - .../boilerplate_web.browser.html | 28 - .../boilerplate_web.cordova.html | 43 - .../local/build/programs/server/boot-utils.js | 7 - .../local/build/programs/server/boot.js | 263 - .../local/build/programs/server/config.json | 6 - .../local/build/programs/server/mini-files.js | 108 - .../build/programs/server/npm-shrinkwrap.json | 40 - .../local/build/programs/server/package.json | 14 - .../programs/server/packages/autopublish.js | 14 - .../server/packages/autopublish.js.map | 1 - .../programs/server/packages/autoupdate.js | 237 - .../server/packages/autoupdate.js.map | 1 - .../build/programs/server/packages/base64.js | 175 - .../programs/server/packages/base64.js.map | 1 - .../programs/server/packages/binary-heap.js | 369 - .../server/packages/binary-heap.js.map | 1 - .../programs/server/packages/blaze-tools.js | 403 - .../server/packages/blaze-tools.js.map | 1 - .../build/programs/server/packages/blaze.js | 2084 -- .../programs/server/packages/blaze.js.map | 1 - .../server/packages/boilerplate-generator.js | 141 - .../packages/boilerplate-generator.js.map | 1 - .../programs/server/packages/callback-hook.js | 139 - .../server/packages/callback-hook.js.map | 1 - .../build/programs/server/packages/check.js | 416 - .../programs/server/packages/check.js.map | 1 - .../build/programs/server/packages/d3js_d3.js | 14 - .../programs/server/packages/d3js_d3.js.map | 1 - .../build/programs/server/packages/ddp.js | 4781 ---- .../build/programs/server/packages/ddp.js.map | 1 - .../build/programs/server/packages/deps.js | 22 - .../programs/server/packages/deps.js.map | 1 - .../build/programs/server/packages/ejson.js | 679 - .../programs/server/packages/ejson.js.map | 1 - .../programs/server/packages/geojson-utils.js | 455 - .../server/packages/geojson-utils.js.map | 1 - .../server/packages/global-imports.js | 28 - .../programs/server/packages/html-tools.js | 3566 --- .../server/packages/html-tools.js.map | 1 - .../build/programs/server/packages/htmljs.js | 664 - .../programs/server/packages/htmljs.js.map | 1 - .../build/programs/server/packages/id-map.js | 110 - .../programs/server/packages/id-map.js.map | 1 - .../programs/server/packages/insecure.js | 14 - .../programs/server/packages/insecure.js.map | 1 - .../build/programs/server/packages/jquery.js | 14 - .../programs/server/packages/jquery.js.map | 1 - .../build/programs/server/packages/json.js | 14 - .../programs/server/packages/json.js.map | 1 - .../programs/server/packages/livedata.js | 23 - .../programs/server/packages/livedata.js.map | 1 - .../build/programs/server/packages/logging.js | 309 - .../programs/server/packages/logging.js.map | 1 - .../server/packages/meteor-platform.js | 15 - .../server/packages/meteor-platform.js.map | 1 - .../build/programs/server/packages/meteor.js | 1242 - .../programs/server/packages/meteor.js.map | 1 - .../programs/server/packages/minimongo.js | 4420 --- .../programs/server/packages/minimongo.js.map | 1 - .../server/packages/momentjs_moment.js | 3249 --- .../server/packages/momentjs_moment.js.map | 1 - .../build/programs/server/packages/mongo.js | 4491 ---- .../programs/server/packages/mongo.js.map | 1 - .../server/packages/mquandalle_jade.js | 14 - .../server/packages/mquandalle_jade.js.map | 1 - .../programs/server/packages/mrt_topojson.js | 32 - .../server/packages/mrt_topojson.js.map | 1 - .../server/packages/numeral_numeral.js | 979 - .../server/packages/numeral_numeral.js.map | 1 - .../server/packages/observe-sequence.js | 384 - .../server/packages/observe-sequence.js.map | 1 - .../programs/server/packages/ordered-dict.js | 241 - .../server/packages/ordered-dict.js.map | 1 - .../build/programs/server/packages/random.js | 285 - .../programs/server/packages/random.js.map | 1 - .../programs/server/packages/reactive-var.js | 129 - .../server/packages/reactive-var.js.map | 1 - .../build/programs/server/packages/reload.js | 14 - .../programs/server/packages/reload.js.map | 1 - .../build/programs/server/packages/retry.js | 97 - .../programs/server/packages/retry.js.map | 1 - .../programs/server/packages/routepolicy.js | 161 - .../server/packages/routepolicy.js.map | 1 - .../build/programs/server/packages/session.js | 14 - .../programs/server/packages/session.js.map | 1 - .../server/packages/spacebars-compiler.js | 1190 - .../server/packages/spacebars-compiler.js.map | 1 - .../programs/server/packages/spacebars.js | 316 - .../programs/server/packages/spacebars.js.map | 1 - .../server/packages/stevezhu_lodash.js | 33 - .../server/packages/stevezhu_lodash.js.map | 1 - .../programs/server/packages/templating.js | 19 - .../server/packages/templating.js.map | 1 - .../build/programs/server/packages/tracker.js | 660 - .../programs/server/packages/tracker.js.map | 1 - .../build/programs/server/packages/ui.js | 25 - .../build/programs/server/packages/ui.js.map | 1 - .../programs/server/packages/underscore.js | 1372 - .../server/packages/underscore.js.map | 1 - .../server/packages/webapp-hashing.js | 71 - .../server/packages/webapp-hashing.js.map | 1 - .../build/programs/server/packages/webapp.js | 831 - .../programs/server/packages/webapp.js.map | 1 - .../local/build/programs/server/program.json | 256 - .../build/programs/server/shell-server.js | 290 - ...a7bab845d191184a9124b7dd8a3472c9b4aa7e.css | 7780 ------ ...b845d191184a9124b7dd8a3472c9b4aa7e.css.map | 2 - .../programs/web.browser/app/client/js/app.js | 26 - .../web.browser/app/client/js/controllers.js | 670 - .../app/client/js/helperFunctions.js | 24 - .../app/client/js/lib/bootstrap.min.js | 14 - .../app/client/js/lib/d3.tip.min.js | 3 - .../app/client/js/lib/datamaps.min.js | 4 - .../app/client/js/lib/jquery.sparkline.js | 3056 --- .../app/client/js/lib/jquery.sparkline.min.js | 7 - .../app/client/js/lib/moment.en.min.js | 3 - .../web.browser/app/client/js/lib/moment.js | 3113 --- .../app/client/js/lib/moment.min.js | 9 - .../app/client/js/lib/primus.min.js | 3 - .../app/client/js/lib/toastr.min.js | 3 - .../web.browser/app/client/js/script.js | 38 - .../app/client/js/templateHelpers.js | 649 - .../app/client/views/error.jade.js | 14 - .../app/client/views/index.jade.js | 515 - .../app/client/views/indexMeteor.js | 331 - .../app/client/views/template.indexMeteor.js | 603 - .../app/client/views/template.layout.js | 8 - .../app/fonts/Simple-Line-Icons.ttf | Bin 35304 -> 0 bytes .../web.browser/app/fonts/minimal-icons.eot | Bin 10972 -> 0 bytes .../web.browser/app/fonts/minimal-icons.svg | 33 - .../web.browser/app/fonts/minimal-icons.ttf | Bin 10784 -> 0 bytes .../web.browser/app/fonts/minimal-icons.woff | Bin 7008 -> 0 bytes .../web.browser/app/images/favicon.ico | Bin 574 -> 0 bytes .../web.browser/app/images/favicon.png | Bin 574 -> 0 bytes .../app/images/screenshot-v0.0.1.jpg | Bin 453110 -> 0 bytes .../app/images/screenshot-v0.0.2.jpg | Bin 739651 -> 0 bytes .../app/images/screenshot-v0.0.5.jpg | Bin 901963 -> 0 bytes .../web.browser/app/images/screenshot.jpg | Bin 1109187 -> 0 bytes .../build/programs/web.browser/head.html | 4 - .../web.browser/packages/autopublish.js | 29 - .../web.browser/packages/autopublish.js.map | 2 - .../web.browser/packages/autoupdate.js | 204 - .../web.browser/packages/autoupdate.js.map | 2 - .../programs/web.browser/packages/base64.js | 190 - .../web.browser/packages/base64.js.map | 2 - .../programs/web.browser/packages/blaze.js | 3609 --- .../web.browser/packages/blaze.js.map | 2 - .../programs/web.browser/packages/check.js | 431 - .../web.browser/packages/check.js.map | 2 - .../programs/web.browser/packages/d3js_d3.js | 9544 ------- .../web.browser/packages/d3js_d3.js.map | 2 - .../programs/web.browser/packages/ddp.js | 5208 ---- .../programs/web.browser/packages/ddp.js.map | 2 - .../programs/web.browser/packages/deps.js | 37 - .../programs/web.browser/packages/deps.js.map | 2 - .../programs/web.browser/packages/ejson.js | 695 - .../web.browser/packages/ejson.js.map | 2 - .../web.browser/packages/geojson-utils.js | 470 - .../web.browser/packages/geojson-utils.js.map | 2 - .../web.browser/packages/global-imports.js | 29 - .../programs/web.browser/packages/htmljs.js | 679 - .../web.browser/packages/htmljs.js.map | 2 - .../programs/web.browser/packages/id-map.js | 126 - .../web.browser/packages/id-map.js.map | 2 - .../programs/web.browser/packages/insecure.js | 29 - .../web.browser/packages/insecure.js.map | 2 - .../programs/web.browser/packages/jquery.js | 10415 -------- .../web.browser/packages/jquery.js.map | 2 - .../programs/web.browser/packages/json.js | 553 - .../programs/web.browser/packages/json.js.map | 2 - .../web.browser/packages/launch-screen.js | 139 - .../web.browser/packages/launch-screen.js.map | 2 - .../programs/web.browser/packages/livedata.js | 36 - .../web.browser/packages/livedata.js.map | 2 - .../programs/web.browser/packages/logging.js | 324 - .../web.browser/packages/logging.js.map | 2 - .../web.browser/packages/meteor-platform.js | 31 - .../packages/meteor-platform.js.map | 2 - .../programs/web.browser/packages/meteor.js | 1086 - .../web.browser/packages/meteor.js.map | 2 - .../web.browser/packages/minimongo.js | 4088 --- .../web.browser/packages/minimongo.js.map | 2 - .../web.browser/packages/momentjs_moment.js | 3264 --- .../packages/momentjs_moment.js.map | 2 - .../programs/web.browser/packages/mongo.js | 1232 - .../web.browser/packages/mongo.js.map | 2 - .../web.browser/packages/mquandalle_jade.js | 29 - .../packages/mquandalle_jade.js.map | 2 - .../web.browser/packages/mrt_topojson.js | 578 - .../web.browser/packages/mrt_topojson.js.map | 2 - .../web.browser/packages/numeral_numeral.js | 994 - .../packages/numeral_numeral.js.map | 2 - .../web.browser/packages/observe-sequence.js | 399 - .../packages/observe-sequence.js.map | 2 - .../web.browser/packages/ordered-dict.js | 256 - .../web.browser/packages/ordered-dict.js.map | 2 - .../programs/web.browser/packages/random.js | 300 - .../web.browser/packages/random.js.map | 2 - .../web.browser/packages/reactive-dict.js | 266 - .../web.browser/packages/reactive-dict.js.map | 2 - .../web.browser/packages/reactive-var.js | 144 - .../web.browser/packages/reactive-var.js.map | 2 - .../programs/web.browser/packages/reload.js | 302 - .../web.browser/packages/reload.js.map | 2 - .../programs/web.browser/packages/retry.js | 112 - .../web.browser/packages/retry.js.map | 2 - .../programs/web.browser/packages/session.js | 100 - .../web.browser/packages/session.js.map | 2 - .../web.browser/packages/spacebars.js | 437 - .../web.browser/packages/spacebars.js.map | 2 - .../web.browser/packages/stevezhu_lodash.js | 12625 --------- .../packages/stevezhu_lodash.js.map | 2 - .../web.browser/packages/templating.js | 129 - .../web.browser/packages/templating.js.map | 2 - .../programs/web.browser/packages/tracker.js | 675 - .../web.browser/packages/tracker.js.map | 2 - .../build/programs/web.browser/packages/ui.js | 40 - .../programs/web.browser/packages/ui.js.map | 2 - .../web.browser/packages/underscore.js | 1387 - .../web.browser/packages/underscore.js.map | 2 - .../programs/web.browser/packages/webapp.js | 62 - .../web.browser/packages/webapp.js.map | 2 - .../build/programs/web.browser/program.json | 761 - .../local/build/server/.bundle_version.txt | 1 - web-app/.meteor/local/build/star.json | 19 - web-app/.meteor/local/db/METEOR-PORT | 1 - web-app/.meteor/local/db/local.0 | Bin 16777216 -> 0 bytes web-app/.meteor/local/db/local.1 | Bin 33554432 -> 0 bytes web-app/.meteor/local/db/local.ns | Bin 16777216 -> 0 bytes web-app/.meteor/local/db/mongod.lock | 0 web-app/.meteor/local/shell/info.json | 1 - 275 files changed, 178288 deletions(-) delete mode 100644 src-lite/css/animation.css delete mode 100755 src-lite/css/bootstrap.min.css delete mode 100644 src-lite/css/minimal-icons-codes.css delete mode 100644 src-lite/css/minimal-icons-embedded.css delete mode 100644 src-lite/css/minimal-icons-ie7-codes.css delete mode 100644 src-lite/css/minimal-icons-ie7.css delete mode 100644 src-lite/css/minimal-icons.css delete mode 100644 src-lite/css/style.css delete mode 100644 src-lite/css/toastr.min.css delete mode 100755 src-lite/fonts/Simple-Line-Icons.ttf delete mode 100644 src-lite/fonts/minimal-icons.eot delete mode 100644 src-lite/fonts/minimal-icons.svg delete mode 100644 src-lite/fonts/minimal-icons.ttf delete mode 100644 src-lite/fonts/minimal-icons.woff delete mode 100644 src-lite/images/favicon.ico delete mode 100644 src-lite/images/favicon.png delete mode 100644 src-lite/js/app.js delete mode 100644 src-lite/js/controllers.js delete mode 100644 src-lite/js/directives.js delete mode 100644 src-lite/js/filters.js delete mode 100644 src-lite/js/lib/angular.js delete mode 100644 src-lite/js/lib/angular.min.js delete mode 100644 src-lite/js/lib/angular.min.js.map delete mode 100755 src-lite/js/lib/bootstrap.min.js delete mode 100644 src-lite/js/lib/d3.js delete mode 100644 src-lite/js/lib/d3.min.js delete mode 100644 src-lite/js/lib/d3.tip.min.js delete mode 100644 src-lite/js/lib/jquery-1.11.3.js delete mode 100644 src-lite/js/lib/jquery-1.11.3.min.js delete mode 100644 src-lite/js/lib/jquery-1.11.3.min.js.map delete mode 100644 src-lite/js/lib/jquery.sparkline.js delete mode 100644 src-lite/js/lib/jquery.sparkline.min.js delete mode 100644 src-lite/js/lib/lodash.js delete mode 100644 src-lite/js/lib/lodash.min.js delete mode 100644 src-lite/js/lib/moment.en.min.js delete mode 100644 src-lite/js/lib/moment.js delete mode 100644 src-lite/js/lib/moment.min.js delete mode 100644 src-lite/js/lib/primus.min.js delete mode 100644 src-lite/js/lib/toastr.min.js delete mode 100644 src-lite/js/script.js delete mode 100644 src-lite/views/index.jade delete mode 100644 src-lite/views/layout.jade delete mode 100644 web-app/.meteor/local/build/README delete mode 100644 web-app/.meteor/local/build/main.js delete mode 100644 web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.browser.html delete mode 100644 web-app/.meteor/local/build/programs/server/assets/packages/boilerplate-generator/boilerplate_web.cordova.html delete mode 100644 web-app/.meteor/local/build/programs/server/boot-utils.js delete mode 100644 web-app/.meteor/local/build/programs/server/boot.js delete mode 100644 web-app/.meteor/local/build/programs/server/config.json delete mode 100644 web-app/.meteor/local/build/programs/server/mini-files.js delete mode 100644 web-app/.meteor/local/build/programs/server/npm-shrinkwrap.json delete mode 100644 web-app/.meteor/local/build/programs/server/package.json delete mode 100644 web-app/.meteor/local/build/programs/server/packages/autopublish.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/autopublish.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/autoupdate.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/autoupdate.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/base64.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/base64.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/binary-heap.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/binary-heap.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/blaze-tools.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/blaze-tools.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/blaze.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/blaze.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/boilerplate-generator.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/callback-hook.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/callback-hook.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/check.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/check.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/d3js_d3.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/d3js_d3.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ddp.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ddp.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/deps.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/deps.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ejson.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ejson.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/geojson-utils.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/geojson-utils.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/global-imports.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/html-tools.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/html-tools.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/htmljs.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/htmljs.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/id-map.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/id-map.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/insecure.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/insecure.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/jquery.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/jquery.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/json.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/json.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/livedata.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/livedata.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/logging.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/logging.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/meteor-platform.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/meteor-platform.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/meteor.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/meteor.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/minimongo.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/minimongo.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/momentjs_moment.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mongo.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mongo.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mquandalle_jade.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/mrt_topojson.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/numeral_numeral.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/observe-sequence.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/observe-sequence.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ordered-dict.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ordered-dict.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/random.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/random.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/reactive-var.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/reactive-var.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/reload.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/reload.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/retry.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/retry.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/routepolicy.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/routepolicy.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/session.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/session.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/spacebars-compiler.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/spacebars-compiler.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/spacebars.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/spacebars.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/stevezhu_lodash.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/stevezhu_lodash.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/templating.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/templating.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/tracker.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/tracker.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ui.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/ui.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/underscore.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/underscore.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/webapp-hashing.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/webapp-hashing.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/packages/webapp.js delete mode 100644 web-app/.meteor/local/build/programs/server/packages/webapp.js.map delete mode 100644 web-app/.meteor/local/build/programs/server/program.json delete mode 100644 web-app/.meteor/local/build/programs/server/shell-server.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/76a7bab845d191184a9124b7dd8a3472c9b4aa7e.css delete mode 100644 web-app/.meteor/local/build/programs/web.browser/76a7bab845d191184a9124b7dd8a3472c9b4aa7e.css.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/app.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/controllers.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/helperFunctions.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/bootstrap.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/d3.tip.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/datamaps.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/jquery.sparkline.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/jquery.sparkline.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/moment.en.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/moment.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/moment.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/primus.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/lib/toastr.min.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/script.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/js/templateHelpers.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/views/error.jade.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/views/index.jade.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/views/indexMeteor.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/views/template.indexMeteor.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/client/views/template.layout.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/fonts/Simple-Line-Icons.ttf delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/fonts/minimal-icons.eot delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/fonts/minimal-icons.svg delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/fonts/minimal-icons.ttf delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/fonts/minimal-icons.woff delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/favicon.ico delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/favicon.png delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/screenshot-v0.0.1.jpg delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/screenshot-v0.0.2.jpg delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/screenshot-v0.0.5.jpg delete mode 100644 web-app/.meteor/local/build/programs/web.browser/app/images/screenshot.jpg delete mode 100644 web-app/.meteor/local/build/programs/web.browser/head.html delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/autopublish.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/autopublish.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/autoupdate.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/autoupdate.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/base64.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/base64.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/blaze.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/blaze.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/check.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/check.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/d3js_d3.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/d3js_d3.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ddp.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ddp.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/deps.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/deps.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ejson.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ejson.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/geojson-utils.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/geojson-utils.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/global-imports.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/htmljs.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/htmljs.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/id-map.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/id-map.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/insecure.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/insecure.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/jquery.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/jquery.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/json.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/json.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/launch-screen.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/launch-screen.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/livedata.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/livedata.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/logging.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/logging.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/meteor-platform.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/meteor-platform.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/meteor.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/meteor.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/minimongo.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/minimongo.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/momentjs_moment.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/momentjs_moment.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mongo.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mongo.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mquandalle_jade.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mquandalle_jade.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mrt_topojson.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/mrt_topojson.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/numeral_numeral.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/numeral_numeral.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/observe-sequence.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/observe-sequence.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ordered-dict.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ordered-dict.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/random.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/random.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reactive-dict.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reactive-dict.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reactive-var.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reactive-var.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reload.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/reload.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/retry.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/retry.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/session.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/session.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/spacebars.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/spacebars.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/stevezhu_lodash.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/stevezhu_lodash.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/templating.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/templating.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/tracker.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/tracker.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ui.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/ui.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/underscore.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/underscore.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/webapp.js delete mode 100644 web-app/.meteor/local/build/programs/web.browser/packages/webapp.js.map delete mode 100644 web-app/.meteor/local/build/programs/web.browser/program.json delete mode 100644 web-app/.meteor/local/build/server/.bundle_version.txt delete mode 100644 web-app/.meteor/local/build/star.json delete mode 100644 web-app/.meteor/local/db/METEOR-PORT delete mode 100644 web-app/.meteor/local/db/local.0 delete mode 100644 web-app/.meteor/local/db/local.1 delete mode 100644 web-app/.meteor/local/db/local.ns delete mode 100755 web-app/.meteor/local/db/mongod.lock delete mode 100644 web-app/.meteor/local/shell/info.json diff --git a/src-lite/css/animation.css b/src-lite/css/animation.css deleted file mode 100644 index ac5a956..0000000 --- a/src-lite/css/animation.css +++ /dev/null @@ -1,85 +0,0 @@ -/* - Animation example, for spinners -*/ -.animate-spin { - -moz-animation: spin 2s infinite linear; - -o-animation: spin 2s infinite linear; - -webkit-animation: spin 2s infinite linear; - animation: spin 2s infinite linear; - display: inline-block; -} -@-moz-keyframes spin { - 0% { - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -moz-transform: rotate(359deg); - -o-transform: rotate(359deg); - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@-webkit-keyframes spin { - 0% { - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -moz-transform: rotate(359deg); - -o-transform: rotate(359deg); - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@-o-keyframes spin { - 0% { - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -moz-transform: rotate(359deg); - -o-transform: rotate(359deg); - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@-ms-keyframes spin { - 0% { - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -moz-transform: rotate(359deg); - -o-transform: rotate(359deg); - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes spin { - 0% { - -moz-transform: rotate(0deg); - -o-transform: rotate(0deg); - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - - 100% { - -moz-transform: rotate(359deg); - -o-transform: rotate(359deg); - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} diff --git a/src-lite/css/bootstrap.min.css b/src-lite/css/bootstrap.min.css deleted file mode 100755 index a376ff5..0000000 --- a/src-lite/css/bootstrap.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Bootstrap v3.3.1 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -/*! - * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=cf8e15f9354657212a08) - * Config saved to config.json and https://gist.github.com/cf8e15f9354657212a08 - *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;-webkit-box-shadow:none !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Source Sans Pro",sans-serif;font-size:16px;line-height:1.42857143;color:#fff;background-color:#000}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#000;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:22px;margin-bottom:22px;border:0;border-top:1px solid #fff}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:200;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#fff}h1,.h1,h2,.h2,h3,.h3{margin-top:22px;margin-bottom:11px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:11px;margin-bottom:11px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:41px}h2,.h2{font-size:34px}h3,.h3{font-size:28px}h4,.h4{font-size:20px}h5,.h5{font-size:16px}h6,.h6{font-size:14px}p{margin:0 0 11px}.lead{margin-bottom:22px;font-size:18px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:24px}}small,.small{font-size:87%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#fff}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#7bcc3a}a.text-success:hover{color:#63a82b}.text-info{color:#10a0de}a.text-info:hover{color:#0d7eae}.text-warning{color:#ffd162}a.text-warning:hover{color:#ffc22f}.text-danger{color:#f74b4b}a.text-danger:hover{color:#f51a1a}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:10px;margin:44px 0 22px;border-bottom:1px solid #fff}ul,ol{margin-top:0;margin-bottom:11px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:22px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #fff}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:11px 22px;margin:0 0 22px;font-size:20px;border-left:5px solid #fff}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#fff}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #fff;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:22px;font-style:normal;line-height:1.42857143}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#fff;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:22px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #333}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #333}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #333}.table .table{background-color:#000}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #333}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #333}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#050505}.table-hover>tbody>tr:hover{background-color:#0a0a0a}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#0a0a0a}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#000}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:16.5px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #333}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:22px;font-size:24px;line-height:inherit;color:#fff;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:16px;line-height:1.42857143;color:#fff}.form-control{display:block;width:100%;height:36px;padding:6px 12px;font-size:16px;line-height:1.42857143;color:#fff;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#fff;opacity:1}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"],input[type="time"],input[type="datetime-local"],input[type="month"]{line-height:36px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm{line-height:33px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg{line-height:49px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:22px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm,.form-group-sm .form-control{height:33px;padding:5px 10px;font-size:14px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:33px;line-height:33px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:49px;padding:10px 16px;font-size:20px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:49px;line-height:49px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:45px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:36px;height:36px;line-height:36px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:49px;height:49px;line-height:49px}.input-sm+.form-control-feedback{width:33px;height:33px;line-height:33px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#7bcc3a}.has-success .form-control{border-color:#7bcc3a;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#63a82b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #b1e18b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #b1e18b}.has-success .input-group-addon{color:#7bcc3a;border-color:#7bcc3a;background-color:#dff0d8}.has-success .form-control-feedback{color:#7bcc3a}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#ffd162}.has-warning .form-control{border-color:#ffd162;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#ffc22f;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ffefc8;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ffefc8}.has-warning .input-group-addon{color:#ffd162;border-color:#ffd162;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#ffd162}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#f74b4b}.has-error .form-control{border-color:#f74b4b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#f51a1a;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fbadad;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fbadad}.has-error .input-group-addon{color:#f74b4b;border-color:#f74b4b;background-color:#f2dede}.has-error .form-control-feedback{color:#f74b4b}.has-feedback label~.form-control-feedback{top:27px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#fff}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:29px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:16px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#7bcc3a;border-color:#6fbc31}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#63a82b;border-color:#528b24}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#7bcc3a;border-color:#6fbc31}.btn-success .badge{color:#7bcc3a;background-color:#fff}.btn-info{color:#fff;background-color:#10a0de;border-color:#0e8fc6}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#0d7eae;border-color:#0a668d}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#10a0de;border-color:#0e8fc6}.btn-info .badge{color:#10a0de;background-color:#fff}.btn-warning{color:#fff;background-color:#ffd162;border-color:#ffca48}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ffc22f;border-color:#ffb80b}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#ffd162;border-color:#ffca48}.btn-warning .badge{color:#ffd162;background-color:#fff}.btn-danger{color:#fff;background-color:#f74b4b;border-color:#f63333}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#f51a1a;border-color:#e10a0a}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#f74b4b;border-color:#f63333}.btn-danger .badge{color:#f74b4b;background-color:#fff}.btn-link{color:#337ab7;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#fff;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:20px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:14px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:14px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:16px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:10px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#fff;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#f2f2f2;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#fff}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:14px;line-height:1.42857143;color:#fff;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:49px;padding:10px 16px;font-size:20px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:49px;line-height:49px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:33px;padding:5px 10px;font-size:14px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:33px;line-height:33px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:16px;font-weight:normal;line-height:1;color:#fff;text-align:center;background-color:#fff;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:14px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:20px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#fff}.nav>li.disabled>a{color:#fff}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#fff;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#fff;border-color:#337ab7}.nav .nav-divider{height:1px;margin:10px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#fff #fff #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#fff;background-color:#000;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#000}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#000}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:22px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block !important;visibility:visible !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:14px 15px;font-size:20px;line-height:22px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:22px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:22px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:14px;padding-bottom:14px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:7px;margin-bottom:7px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:7px;margin-bottom:7px}.navbar-btn.btn-sm{margin-top:8.5px;margin-bottom:8.5px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:14px;margin-bottom:14px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .navbar-nav>li>a{color:#fff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#fff}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#fff}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.pager{padding-left:0;margin:22px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#fff}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#fff;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#fff}.label-default[href]:hover,.label-default[href]:focus{background-color:#e6e6e6}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#7bcc3a}.label-success[href]:hover,.label-success[href]:focus{background-color:#63a82b}.label-info{background-color:#10a0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#0d7eae}.label-warning{background-color:#ffd162}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ffc22f}.label-danger{background-color:#f74b4b}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#f51a1a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:14px;font-weight:bold;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#fff;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#fff}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:24px;font-weight:200}.jumbotron>hr{border-top-color:#e6e6e6}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:72px}}.alert{padding:15px;margin-bottom:22px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#7bcc3a}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#63a82b}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#10a0de}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#0d7eae}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#ffd162}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#ffc22f}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#f74b4b}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#f51a1a}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:22px;margin-bottom:22px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0%;height:100%;font-size:14px;line-height:22px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#7bcc3a}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#10a0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#ffd162}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#f74b4b}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;color:#555;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#fff;color:#fff;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#fff}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#7bcc3a;background-color:#dff0d8}a.list-group-item-success{color:#7bcc3a}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#7bcc3a;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#7bcc3a;border-color:#7bcc3a}.list-group-item-info{color:#10a0de;background-color:#d9edf7}a.list-group-item-info{color:#10a0de}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#10a0de;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#10a0de;border-color:#10a0de}.list-group-item-warning{color:#ffd162;background-color:#fcf8e3}a.list-group-item-warning{color:#ffd162}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#ffd162;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#ffd162;border-color:#ffd162}.list-group-item-danger{color:#f74b4b;background-color:#f2dede}a.list-group-item-danger{color:#f74b4b}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#f74b4b;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#f74b4b;border-color:#f74b4b}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.close{float:right;font-size:24px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:absolute;top:0;right:0;left:0;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.42857143px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;visibility:visible;font-family:"Source Sans Pro",sans-serif;font-size:14px;font-weight:normal;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#000;text-align:center;text-decoration:none;background-color:#fff;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#fff}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#fff}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#fff}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#fff}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#fff}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#fff}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#fff}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#fff}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Source Sans Pro",sans-serif;font-size:16px;font-weight:normal;line-height:1.42857143;text-align:left;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:16px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-webkit-gradient(linear, left top, right top, color-stop(0, rgba(0,0,0,0.5)), to(rgba(0,0,0,0.0001)));background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-webkit-gradient(linear, left top, right top, color-stop(0, rgba(0,0,0,0.0001)), to(rgba(0,0,0,0.5)));background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}} \ No newline at end of file diff --git a/src-lite/css/minimal-icons-codes.css b/src-lite/css/minimal-icons-codes.css deleted file mode 100644 index 263c0a3..0000000 --- a/src-lite/css/minimal-icons-codes.css +++ /dev/null @@ -1,23 +0,0 @@ - -.icon-truck:before { content: '\e800'; } /* '' */ -.icon-database:before { content: '\e801'; } /* '' */ -.icon-mining:before { content: '\e802'; } /* '' */ -.icon-check:before { content: '\e803'; } /* '' */ -.icon-cancel:before { content: '\e804'; } /* '' */ -.icon-loader:before { content: '\e805'; } /* '' */ -.icon-check-o:before { content: '\e806'; } /* '' */ -.icon-cancel-o:before { content: '\e807'; } /* '' */ -.icon-warning-o:before { content: '\e808'; } /* '' */ -.icon-network:before { content: '\e809'; } /* '' */ -.icon-block:before { content: '\e80a'; } /* '' */ -.icon-bulb:before { content: '\e80b'; } /* '' */ -.icon-node:before { content: '\e80c'; } /* '' */ -.icon-laptop:before { content: '\e80d'; } /* '' */ -.icon-time:before { content: '\e80e'; } /* '' */ -.icon-clock:before { content: '\e80f'; } /* '' */ -.icon-group:before { content: '\e810'; } /* '' */ -.icon-gas:before { content: '\e811'; } /* '' */ -.icon-difficulty:before { content: '\e812'; } /* '' */ -.icon-uncle:before { content: '\e813'; } /* '' */ -.icon-hashrate:before { content: '\e814'; } /* '' */ -.icon-gasprice:before { content: '\e815'; } /* '' */ \ No newline at end of file diff --git a/src-lite/css/minimal-icons-embedded.css b/src-lite/css/minimal-icons-embedded.css deleted file mode 100644 index 21d871f..0000000 --- a/src-lite/css/minimal-icons-embedded.css +++ /dev/null @@ -1,76 +0,0 @@ -@font-face { - font-family: 'minimal-icons'; - src: url('../fonts/minimal-icons.eot?59779169'); - src: url('../fonts/minimal-icons.eot?59779169#iefix') format('embedded-opentype'), - url('../fonts/minimal-icons.svg?59779169#minimal-icons') format('svg'); - font-weight: normal; - font-style: normal; -} -@font-face { - font-family: 'minimal-icons'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,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ABawBCWwBCYgLkcjRyNhsAlDKyMgPCAuIzixKwEUKy2wQSyxCAQlQrAAFrAEJbAEJSAuRyNHI2EgsAQjQrAJQysgsGBQWCCwQFFYswIgAyAbswImAxpZQkIjIEewBEOwAmIgsABQWLBAYFlmsAFjYCCwASsgiophILACQ2BkI7ADQ2FkUFiwAkNhG7ADQ2BZsAMlsAJiILAAUFiwQGBZZrABY2GwAiVGYTgjIDwjOBshICBGI0ewASsjYTghWbErARQrLbBCLLA1Ky6xKwEUKy2wQyywNishIyAgPLAEI0IjOLErARQrsARDLrArKy2wRCywABUgR7AAI0KyAAEBFRQTLrAxKi2wRSywABUgR7AAI0KyAAEBFRQTLrAxKi2wRiyxAAEUE7AyKi2wRyywNCotsEgssAAWRSMgLiBGiiNhOLErARQrLbBJLLAII0KwSCstsEossgAAQSstsEsssgABQSstsEwssgEAQSstsE0ssgEBQSstsE4ssgAAQistsE8ssgABQistsFAssgEAQistsFEssgEBQistsFIssgAAPistsFMssgABPistsFQssgEAPistsFUssgEBPistsFYssgAAQCstsFcssgABQCstsFgssgEAQCstsFkssgEBQCstsFossgAAQystsFsssgABQystsFwssgEAQystsF0ssgEBQystsF4ssgAAPystsF8ssgABPystsGAssgEAPystsGEssgEBPystsGIssDcrLrErARQrLbBjLLA3K7A7Ky2wZCywNyuwPCstsGUssAAWsDcrsD0rLbBmLLA4Ky6xKwEUKy2wZyywOCuwOystsGgssDgrsDwrLbBpLLA4K7A9Ky2waiywOSsusSsBFCstsGsssDkrsDsrLbBsLLA5K7A8Ky2wbSywOSuwPSstsG4ssDorLrErARQrLbBvLLA6K7A7Ky2wcCywOiuwPCstsHEssDorsD0rLbByLLMJBAIDRVghGyMhWUIrsAhlsAMkUHiwARUwLQBLuADIUlixAQGOWbABuQgACABjcLEABUKxAAAqsQAFQrEACCqxAAVCsQAIKrEABUK5AAAACSqxAAVCuQAAAAkqsQMARLEkAYhRWLBAiFixA2REsSYBiFFYugiAAAEEQIhjVFixAwBEWVlZWbEADCq4Af+FsASNsQIARAA=') format('truetype'); -} -/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ -/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ -/* -@media screen and (-webkit-min-device-pixel-ratio:0) { - @font-face { - font-family: 'minimal-icons'; - src: url('../fonts/minimal-icons.svg?59779169#minimal-icons') format('svg'); - } -} -*/ - - [class^="icon-"]:before, [class*=" icon-"]:before { - font-family: "minimal-icons"; - font-style: normal; - font-weight: normal; - speak: none; - - display: inline-block; - text-decoration: inherit; - width: 1em; - margin-right: .2em; - text-align: center; - /* opacity: .8; */ - - /* For safety - reset parent styles, that can break glyph codes*/ - font-variant: normal; - text-transform: none; - - /* fix buttons height, for twitter bootstrap */ - line-height: 1em; - - /* Animation center compensation - margins should be symmetric */ - /* remove if not needed */ - margin-left: .2em; - - /* you can be more comfortable with increased icons size */ - /* font-size: 120%; */ - - /* Uncomment for 3D effect */ - /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ -} -.icon-truck:before { content: '\e800'; } /* '' */ -.icon-database:before { content: '\e801'; } /* '' */ -.icon-mining:before { content: '\e802'; } /* '' */ -.icon-check:before { content: '\e803'; } /* '' */ -.icon-cancel:before { content: '\e804'; } /* '' */ -.icon-loader:before { content: '\e805'; } /* '' */ -.icon-check-o:before { content: '\e806'; } /* '' */ -.icon-cancel-o:before { content: '\e807'; } /* '' */ -.icon-warning-o:before { content: '\e808'; } /* '' */ -.icon-network:before { content: '\e809'; } /* '' */ -.icon-block:before { content: '\e80a'; } /* '' */ -.icon-bulb:before { content: '\e80b'; } /* '' */ -.icon-node:before { content: '\e80c'; } /* '' */ -.icon-laptop:before { content: '\e80d'; } /* '' */ -.icon-time:before { content: '\e80e'; } /* '' */ -.icon-clock:before { content: '\e80f'; } /* '' */ -.icon-group:before { content: '\e810'; } /* '' */ -.icon-gas:before { content: '\e811'; } /* '' */ -.icon-difficulty:before { content: '\e812'; } /* '' */ -.icon-uncle:before { content: '\e813'; } /* '' */ -.icon-hashrate:before { content: '\e814'; } /* '' */ -.icon-gasprice:before { content: '\e815'; } /* '' */ \ No newline at end of file diff --git a/src-lite/css/minimal-icons-ie7-codes.css b/src-lite/css/minimal-icons-ie7-codes.css deleted file mode 100644 index 8815a66..0000000 --- a/src-lite/css/minimal-icons-ie7-codes.css +++ /dev/null @@ -1,23 +0,0 @@ - -.icon-truck { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-database { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-mining { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-check { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-loader { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-check-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-cancel-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-warning-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-network { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-block { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-bulb { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-node { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-laptop { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-time { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-clock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-group { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-gas { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-difficulty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-uncle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-hashrate { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-gasprice { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/src-lite/css/minimal-icons-ie7.css b/src-lite/css/minimal-icons-ie7.css deleted file mode 100644 index 84250d5..0000000 --- a/src-lite/css/minimal-icons-ie7.css +++ /dev/null @@ -1,34 +0,0 @@ -[class^="icon-"], [class*=" icon-"] { - font-family: 'minimal-icons'; - font-style: normal; - font-weight: normal; - - /* fix buttons height */ - line-height: 1em; - - /* you can be more comfortable with increased icons size */ - /* font-size: 120%; */ -} - -.icon-truck { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-database { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-mining { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-check { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-loader { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-check-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-cancel-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-warning-o { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-network { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-block { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-bulb { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-node { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-laptop { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-time { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-clock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-group { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-gas { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-difficulty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-uncle { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-hashrate { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } -.icon-gasprice { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } \ No newline at end of file diff --git a/src-lite/css/minimal-icons.css b/src-lite/css/minimal-icons.css deleted file mode 100644 index f0aa008..0000000 --- a/src-lite/css/minimal-icons.css +++ /dev/null @@ -1,78 +0,0 @@ -@font-face { - font-family: 'minimal-icons'; - src: url('../fonts/minimal-icons.eot?7541141'); - src: url('../fonts/minimal-icons.eot?7541141#iefix') format('embedded-opentype'), - url('../fonts/minimal-icons.woff?7541141') format('woff'), - url('../fonts/minimal-icons.ttf?7541141') format('truetype'), - url('../fonts/minimal-icons.svg?7541141#minimal-icons') format('svg'); - font-weight: normal; - font-style: normal; -} -/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ -/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ -/* -@media screen and (-webkit-min-device-pixel-ratio:0) { - @font-face { - font-family: 'minimal-icons'; - src: url('../fonts/minimal-icons.svg?7541141#minimal-icons') format('svg'); - } -} -*/ - - [class^="icon-"]:before, [class*=" icon-"]:before { - font-family: "minimal-icons"; - font-style: normal; - font-weight: normal; - speak: none; - - display: inline-block; - text-decoration: inherit; - width: 1em; - margin-right: .2em; - text-align: center; - /* opacity: .8; */ - - /* For safety - reset parent styles, that can break glyph codes*/ - font-variant: normal; - text-transform: none; - - /* fix buttons height, for twitter bootstrap */ - line-height: 1em; - - /* Animation center compensation - margins should be symmetric */ - /* remove if not needed */ - margin-left: .2em; - - /* you can be more comfortable with increased icons size */ - /* font-size: 120%; */ - - /* Font smoothing. That was taken from TWBS */ - /*-webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale;*/ - - /* Uncomment for 3D effect */ - /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ -} - -.icon-truck:before { content: '\e800'; } /* '' */ -.icon-database:before { content: '\e801'; } /* '' */ -.icon-mining:before { content: '\e802'; } /* '' */ -.icon-check:before { content: '\e803'; } /* '' */ -.icon-cancel:before { content: '\e804'; } /* '' */ -.icon-loader:before { content: '\e805'; } /* '' */ -.icon-check-o:before { content: '\e806'; } /* '' */ -.icon-cancel-o:before { content: '\e807'; } /* '' */ -.icon-warning-o:before { content: '\e808'; } /* '' */ -.icon-network:before { content: '\e809'; } /* '' */ -.icon-block:before { content: '\e80a'; } /* '' */ -.icon-bulb:before { content: '\e80b'; } /* '' */ -.icon-node:before { content: '\e80c'; } /* '' */ -.icon-laptop:before { content: '\e80d'; } /* '' */ -.icon-time:before { content: '\e80e'; } /* '' */ -.icon-clock:before { content: '\e80f'; } /* '' */ -.icon-group:before { content: '\e810'; } /* '' */ -.icon-gas:before { content: '\e811'; } /* '' */ -.icon-difficulty:before { content: '\e812'; } /* '' */ -.icon-uncle:before { content: '\e813'; } /* '' */ -.icon-hashrate:before { content: '\e814'; } /* '' */ -.icon-gasprice:before { content: '\e815'; } /* '' */ \ No newline at end of file diff --git a/src-lite/css/style.css b/src-lite/css/style.css deleted file mode 100644 index af6989e..0000000 --- a/src-lite/css/style.css +++ /dev/null @@ -1,468 +0,0 @@ -html { - width: 100%; -} - -body { - width: 100%; - font-smooth: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -table td { - font-size: 14px; - white-space: nowrap !important; - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; -} - -.propagationBox { - position: relative; - width: 8px; - height: 8px; - float: left; - top: 5px; - margin-right: 5px; - -webkit-border-radius: 2px; - border-radius: 2px; -} - -.bg-success, -.text-success .propagationBox { - background: #7bcc3a; -} - -.bg-info, -.text-info .propagationBox { - background: #10a0de; -} - -.bg-warning, -.text-warning .propagationBox { - background: #FFD162; -} - -.bg-orange, -.text-orange .propagationBox { - background: #ff8a00; -} - -.bg-danger, -.text-danger .propagationBox { - background: #F74B4B; -} - -.text-gray .propagationBox { - background: none !important; - border: 1px solid #777; -} - -.bg-success, -.bg-info, -.bg-warning, -.bg-orange, -.bg-danger { - color: #000; -} - -.text-gray { - color: #777 !important; -} - -.text-orange { - color: #ff8a00; -} - -.container-fluid { - padding-left: 30px; - padding-right: 30px; -} - -.stat-holder { - background: #090909; - border: 1px solid rgba(255,255,255,0.05); -} - -.big-info { - padding-top: 15px; - padding-bottom: 15px; -} - -.big-info .icon-full-width i { - display: block; - width: 85px; - height: 70px; - font-size: 70px; - line-height: 70px; - margin-right: 15px; - margin-left: -15px; -} - -.big-info span.small-title, -.big-info div.small-title-miner { - display: block; -} - -span.small-title, -div.small-title-miner { - font-weight: 700; - font-size: 14px; - line-height: 20px; - letter-spacing: 1px; - text-transform: uppercase; - color: #aaa; -} - -span.small-title span.small { - font-size: 11px; - font-weight: 600; - line-height: 16px; - letter-spacing: 0px; - color: #666; - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; -} - -.big-info .big-details { - display: block; - font-weight: 200; - font-size: 50px; - line-height: 55px; - letter-spacing: -4px; - word-spacing: nowrap !important; -} - -.big-info .big-details .small-hash { - font-size: 87%; -} - -.big-info .big-details-holder { - position: absolute; - top: 15px; - left: 99px; -} - -.big-info.chart { - padding-top: 12px; -} - -.big-info.chart .big-details { - display: block; - position: absolute; - top: 40px; -} - -.big-info.chart { - height: 120px; - -webkit-box-sizing: border-box - box-sizing: border-box; -} - -.big-info.chart.double-chart { - height: 242px; -} - -.blocks-holder { - width: 288px; - padding-top: 6px; - margin-left: -2px; -} - -.blocks-holder { - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; -} - -.blocks-holder div.small-title-miner { - font-family: "Lucida Console", "Courier New", Courier, monospace; - font-size: 11px; - letter-spacing: -0.1px; - text-transform: none; - white-space: nowrap; - color: #777; -} - -.blocks-holder .block-count { - font-family: 'Lucida Console', "Courier New", Courier, monospace; - font-weight: bold; - font-size: 10px; - padding-top: 3px; - float: right; -} - -.blocks-holder .block { - width: 6px; - height: 6px; - margin: 2px 1px 6px 0px; - float: left; - -webkit-border-radius: 1px; - border-radius: 1px; - opacity: .8; -} - -.blocks-holder .block:first-child { - margin-left: 0px; -} - -.blocks-holder .block:last-child { - margin-right: 0px; -} - -.second-row .box { - height: 40px; - line-height: 24px !important; - padding: 5px 15px; -} - -.second-row .box i, -.big-info.chart i { - position: relative; - top: 2px; - left: -3px; - font-size: 24px; - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; - margin-right: 7px; - float: left; -} - -.big-info.chart i { - font-size: 24px; - top: -2px; -} - -.small-value { - font-weight: 300; - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; - float: right; -} - -.second-row .box .small-value { - float: right; -} -.big-info .small-value { - position: absolute; - right: 14px; - top: 10px; -} - -table i { - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; -} - -table th, -table td { - border-color: #222 !important; -} - -table td { - line-height: 18px !important; -} - -table th { - color: #888; -} - -table th i { - line-height: 1em; - font-size: 20px; -} -table td i { - position: relative; - top: 2px; - left: 2px; -} -table td.peerPropagationChart { - padding: 4px 5px !important; -} -nodepropagchart { - display: inline-block; - width: 107px; - height: 20px; - vertical-align: top; -} - -.table>tbody>tr>td, -.table>thead>tr>th { - padding: 5px; -} - -.th-nodecheck, -.td-nodecheck { - width: 38px; - text-align: center; -} - -.td-nodecheck i { - left: 0px; -} - -.th-nodename { - width: 300px; - text-overflow: ellipsis; -} - -.th-nodetype { - width: 220px; -} - -.th-latency { - width: 100px; -} - -.th-blockhash { - width: 150px; -} - -.th-blocktime { - width: 110px; -} - -.th-peerPropagationTime { - width: 120px; -} - -.th-peerPropagationChart { - width: 140px; -} - -.nodeInfo .tooltip .tooltip-inner { - max-width: 400px; - text-align: left; - font-size: 12px; -} - -.map-holder { - padding: 0; -} - -#mapHolder { - position: relative; - display: block; - width: 100%; - height: 282px; - overflow: hidden; -} - -#mapHolder > svg { - right: 0; - bottom: 0; - width: 100%; - height: 100%; - display: inline-block; - position: absolute; - top: 0; - left: 0; -} - -.jqsfield { - position: relative; - padding: 5px 0; - width: auto; - left: -50%; - word-wrap: wrap; - text-align: center; -} - -.d3-tip { - padding: 5px 0; -} - -.jqsfield .tooltip-arrow { - position: absolute; - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #fff; -} - -.datamaps-hoverover .tooltip-arrow, -.d3-tip .tooltip-arrow { - position: absolute; - top: -5px; - left: 0px; - margin-left: -5px; - border-width: 0px 5px 5px 5px; - border-bottom-color: #fff; -} - -.d3-tip .tooltip-arrow { - top: 0px; - left: 50%; -} - -.hoverinfo { - position: relative; - width: auto; - left: -50%; - text-align: center; - color: #333; - border: none !important; - box-shadow: none !important; - border-radius: 3px !important; - padding: 5px !important; - line-height: 14px !important; -} - -.hoverinfo .propagationBox { - top: 3px; -} - -svg { - overflow: visible !important; -} - -svg .bars .bar { - opacity: 1; - shape-rendering: auto; -} - -svg .bars .handle { - opacity: 0; -} - -svg .bars .highlight { - opacity: 0; -} - -svg .bars g:hover .highlight { - opacity: 1; -} - -svg .line { - fill: none; - stroke: #ff0000; - stroke-width: 1.3px; - stroke-linejoin: round; - stroke-linecap: round; - shape-rendering: geometric-precision; - /*-webkit-svg-shadow: 0 0 7px #fff;*/ -} - -svg .bar text { - text-anchor: end; - font-size: 12px; -} - -svg .axis path, -svg .axis line { - fill: none; - stroke: rgba(255,255,255,0.15); - shape-rendering: crispEdges; -} -svg .axis text { - fill: #777; - font-size: 10px; - letter-spacing: 0px; - font-family: "Source Sans Pro"; - font-weight: 700; - -webkit-font-smoothing: subpixel-antialiased; - -moz-osx-font-smoothing: auto; -} - -svg .y.axis .tick:first-child text { - opacity: 0; -} \ No newline at end of file diff --git a/src-lite/css/toastr.min.css b/src-lite/css/toastr.min.css deleted file mode 100644 index 613c47b..0000000 --- a/src-lite/css/toastr.min.css +++ /dev/null @@ -1 +0,0 @@ -.toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#fff}.toast-message a:hover{color:#ccc;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#fff;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:focus,.toast-close-button:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.8;-ms-filter:alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-moz-box-shadow:0 0 12px #000;-webkit-box-shadow:0 0 12px #000;box-shadow:0 0 12px #000;opacity:1;-ms-filter:alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-bottom-center>div,#toast-container.toast-top-center>div{width:300px;margin:auto}#toast-container.toast-bottom-full-width>div,#toast-container.toast-top-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width:240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:241px) and (max-width:480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:481px) and (max-width:768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}} \ No newline at end of file diff --git a/src-lite/fonts/Simple-Line-Icons.ttf b/src-lite/fonts/Simple-Line-Icons.ttf deleted file mode 100755 index 2194f1f87ffb06e2664e4e56e8656060967e4f9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35304 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
aku7a;sRcpljl?pj>s*(x- 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 Y=6j1jlOpxo+1WVP?`OupGy5j|8*ns+>i_@% diff --git a/src-lite/fonts/minimal-icons.eot b/src-lite/fonts/minimal-icons.eot deleted file mode 100644 index 0840f1365b26b28922be340e943296287cd0dcb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10972 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 - - -Copyright (C) 2015 by original authors @ fontello.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src-lite/fonts/minimal-icons.ttf b/src-lite/fonts/minimal-icons.ttf deleted file mode 100644 index dd978d2782c4851d828a12f33c6e0725d1fbaa3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10784 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 NKBAi*#qKad{x1$w7-|3j diff --git a/src-lite/fonts/minimal-icons.woff b/src-lite/fonts/minimal-icons.woff deleted file mode 100644 index 61c453f537e3d544c5048ffbeed8ccf75d53292f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7008 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 diff --git a/src-lite/images/favicon.ico b/src-lite/images/favicon.ico deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| diff --git a/src-lite/images/favicon.png b/src-lite/images/favicon.png deleted file mode 100644 index ca92e19557723fa236841ca40add8fae904c6139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmV-E0>S->P)q;@B<>6 zq;q~?{{VgfFF<|)`~ZFcT}u1`gnxijk#v+PGbatw$vWG6cg8ENEX?_4Z+2(b4gwFG z&1OUR(r1q-@UtC!jUdLo2LR9*mjpg!AWrt;NLiFz>u8WShOyMO{IY6jICgKxBfMP;WvxvuAN z&78<2;8qN1ui~ecWjPho{cAZ!Yl#u77eU|$5P3e>|cNZ04utrj~%_=8UO$Q M07*qoM6N<$f?OZ-`~Uy| diff --git a/src-lite/js/app.js b/src-lite/js/app.js deleted file mode 100644 index a4b7769..0000000 --- a/src-lite/js/app.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -/* Init Angular App */ - -var netStatsApp = angular.module('netStatsApp', ['netStatsApp.filters', 'netStatsApp.directives']); - - -/* Services */ - -netStatsApp.factory('socket', function ($rootScope) { - var socket = new Primus(); - return socket; -}); - -netStatsApp.factory('toastr', function ($rootScope) { - toastr = window.toastr; - toastr.options = { - "closeButton": false, - "debug": false, - "progressBar": false, - "newestOnTop": true, - "positionClass": "toast-top-right", - "preventDuplicates": false, - "onclick": null, - "showDuration": "300", - "hideDuration": "1000", - "timeOut": "5000", - "extendedTimeOut": "1000", - "showEasing": "swing", - "hideEasing": "linear", - "showMethod": "fadeIn", - "hideMethod": "fadeOut" - }; - return toastr; -}); - -netStatsApp.factory('_', function ($rootScope) { - var lodash = window._; - return lodash; -}); diff --git a/src-lite/js/controllers.js b/src-lite/js/controllers.js deleted file mode 100644 index dcbb1ca..0000000 --- a/src-lite/js/controllers.js +++ /dev/null @@ -1,562 +0,0 @@ - -/* Controllers */ - -netStatsApp.controller('StatsCtrl', function($scope, $filter, socket, _, toastr) { - - var MAX_BINS = 40; - - // Main Stats init - // --------------- - - $scope.frontierHash = '0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa'; - $scope.nodesTotal = 0; - $scope.nodesActive = 0; - $scope.bestBlock = 0; - $scope.lastBlock = 0; - $scope.lastDifficulty = 0; - $scope.upTimeTotal = 0; - $scope.avgBlockTime = 0; - $scope.blockPropagationAvg = 0; - $scope.avgHashrate = 0; - $scope.uncleCount = 0; - $scope.bestStats = {}; - - $scope.lastBlocksTime = _.fill(Array(MAX_BINS), 2); - $scope.difficultyChart = _.fill(Array(MAX_BINS), 2); - $scope.transactionDensity = _.fill(Array(MAX_BINS), 2); - $scope.gasSpending = _.fill(Array(MAX_BINS), 2); - $scope.miners = []; - - - $scope.nodes = []; - $scope.map = []; - $scope.blockPropagationChart = []; - $scope.uncleCountChart = _.fill(Array(MAX_BINS), 2); - $scope.coinbases = []; - - $scope.latency = 0; - - $scope.currentApiVersion = "0.0.16"; - - $scope.predicate = ['-pinned', '-stats.active', '-stats.block.number', 'stats.block.propagation']; - $scope.reverse = false; - $scope.pinned = []; - - $scope.prefixPredicate = ['-pinned', '-stats.active']; - $scope.originalPredicate = ['-stats.block.number', 'stats.block.propagation']; - - $scope.orderTable = function(predicate, reverse) - { - if(!_.isEqual(predicate, $scope.originalPredicate)) - { - $scope.reverse = reverse; - $scope.originalPredicate = predicate; - $scope.predicate = _.union($scope.prefixPredicate, predicate); - } - else - { - $scope.reverse = !$scope.reverse; - - if($scope.reverse === true){ - _.forEach(predicate, function (value, key) { - predicate[key] = (value[0] === '-' ? value.replace('-', '') : '-' + value); - }); - } - - $scope.predicate = _.union($scope.prefixPredicate, predicate); - } - } - - $scope.pinNode = function(id) - { - index = findIndex({id: id}); - - if( !_.isUndefined($scope.nodes[index]) ) - { - $scope.nodes[index].pinned = !$scope.nodes[index].pinned; - - if($scope.nodes[index].pinned) - { - $scope.pinned.push(id); - } - else - { - $scope.pinned.splice($scope.pinned.indexOf(id), 1); - } - } - } - - var timeout = setInterval(function () - { - $scope.$apply(); - }, 300); - - $scope.getNumber = function (num) { - return new Array(num); - } - - // Socket listeners - // ---------------- - - socket.on('open', function open() { - socket.emit('ready'); - console.log('The connection has been opened.'); - }) - .on('end', function end() { - console.log('Socket connection ended.') - }) - .on('error', function error(err) { - console.log(err); - }) - .on('reconnecting', function reconnecting(opts) { - console.log('We are scheduling a reconnect operation', opts); - }) - .on('data', function incoming(data) { - $scope.$apply(socketAction(data.action, data.data)); - }); - - socket.on('init', function(data) - { - $scope.$apply(socketAction("init", data.nodes)); - }); - - socket.on('client-latency', function(data) - { - $scope.latency = data.latency; - }) - - function socketAction(action, data) - { - // console.log('Action: ', action); - // console.log('Data: ', data); - - switch(action) - { - case "init": - $scope.nodes = data; - - _.forEach($scope.nodes, function (node, index) { - // Init hashrate - if( _.isUndefined(node.stats.hashrate) ) - node.stats.hashrate = 0; - - // Init latency - latencyFilter(node); - - // Init history - if( _.isUndefined(data.history) ) - { - data.history = new Array(40); - _.fill(data.history, -1); - } - - // Init or recover pin - node.pinned = ($scope.pinned.indexOf(node.id) >= 0 ? true : false); - }); - - if( $scope.nodes.length > 0 ) - { - toastr['success']("Got nodes list", "Got nodes!"); - - updateActiveNodes(); - } - - break; - - case "add": - var index = findIndex({id: data.id}); - - if( addNewNode(data) ) - toastr['success']("New node "+ $scope.nodes[findIndex({id: data.id})].info.name +" connected!", "New node!"); - else - toastr['info']("Node "+ $scope.nodes[index].info.name +" reconnected!", "Node is back!"); - - break; - - // TODO: Remove when everybody updates api client to 0.0.12 - case "update": - var index = findIndex({id: data.id}); - - if( index >= 0 && !_.isUndefined($scope.nodes[index]) && !_.isUndefined($scope.nodes[index].stats) ) - { - if( !_.isUndefined($scope.nodes[index].stats.latency) ) - data.stats.latency = $scope.nodes[index].stats.latency; - - if( _.isUndefined(data.stats.hashrate) ) - data.stats.hashrate = 0; - - if( $scope.nodes[index].stats.block.number < data.stats.block.number ) - { - var best = _.max($scope.nodes, function (node) { - return parseInt(node.stats.block.number); - }).stats.block; - - if (data.stats.block.number > best.number) { - data.stats.block.arrived = _.now(); - } else { - data.stats.block.arrived = best.arrived; - } - - $scope.nodes[index].history = data.history; - } - - $scope.nodes[index].stats = data.stats; - - if( !_.isUndefined(data.stats.latency) && _.get($scope.nodes[index], 'stats.latency', 0) !== data.stats.latency ) - { - $scope.nodes[index].stats.latency = data.stats.latency; - - latencyFilter($scope.nodes[index]); - } - - updateBestBlock(); - } - - break; - - case "block": - var index = findIndex({id: data.id}); - - if( index >= 0 && !_.isUndefined($scope.nodes[index]) && !_.isUndefined($scope.nodes[index].stats) ) - { - if( $scope.nodes[index].stats.block.number < data.block.number ) - { - var best = _.max($scope.nodes, function (node) { - return parseInt(node.stats.block.number); - }).stats.block; - - if (data.block.number > best.number) { - data.block.arrived = _.now(); - } else { - data.block.arrived = best.arrived; - } - - $scope.nodes[index].history = data.history; - } - - $scope.nodes[index].stats.block = data.block; - $scope.nodes[index].stats.propagationAvg = data.propagationAvg; - - updateBestBlock(); - } - - break; - - case "pending": - var index = findIndex({id: data.id}); - - if( !_.isUndefined(data.id) && index >= 0 ) - { - var node = $scope.nodes[index]; - - if( !_.isUndefined(node) && !_.isUndefined(node.stats.pending) && !_.isUndefined(data.pending) ) - $scope.nodes[index].stats.pending = data.pending; - } - - break; - - case "stats": - var index = findIndex({id: data.id}); - - if( !_.isUndefined(data.id) && index >= 0 ) - { - var node = $scope.nodes[index]; - - if( !_.isUndefined(node) && !_.isUndefined(node.stats) ) - { - $scope.nodes[index].stats.active = data.stats.active; - $scope.nodes[index].stats.mining = data.stats.mining; - $scope.nodes[index].stats.hashrate = data.stats.hashrate; - $scope.nodes[index].stats.peers = data.stats.peers; - $scope.nodes[index].stats.gasPrice = data.stats.gasPrice; - $scope.nodes[index].stats.uptime = data.stats.uptime; - - if( !_.isUndefined(data.stats.latency) && _.get($scope.nodes[index], 'stats.latency', 0) !== data.stats.latency ) - { - $scope.nodes[index].stats.latency = data.stats.latency; - - latencyFilter($scope.nodes[index]); - } - - updateActiveNodes(); - } - } - - break; - - case "info": - var index = findIndex({id: data.id}); - - if( index >= 0 ) - { - $scope.nodes[index].info = data.info; - - if( _.isUndefined($scope.nodes[index].pinned) ) - $scope.nodes[index].pinned = false; - - // Init latency - latencyFilter($scope.nodes[index]); - - updateActiveNodes(); - } - - break; - - case "blockPropagationChart": - $scope.blockPropagationChart = data.histogram; - $scope.blockPropagationAvg = data.avg; - - break; - - case "uncleCount": - $scope.uncleCount = data[0] + data[1]; - data.reverse(); - $scope.uncleCountChart = data; - - break; - - case "charts": - if( !_.isEqual($scope.avgBlockTime, data.avgBlocktime) ) - $scope.avgBlockTime = data.avgBlocktime; - - if( !_.isEqual($scope.avgHashrate, data.avgHashrate) ) - $scope.avgHashrate = data.avgHashrate; - - if( !_.isEqual($scope.lastBlocksTime, data.blocktime) && data.blocktime.length >= MAX_BINS ) - $scope.lastBlocksTime = data.blocktime; - - data.uncleCount.reverse(); - - if( !_.isEqual($scope.uncleCountChart, data.uncleCount) && data.uncleCount.length >= MAX_BINS ) { - $scope.uncleCount = data.uncleCount[data.uncleCount.length-2] + data.uncleCount[data.uncleCount.length-1]; - $scope.uncleCountChart = data.uncleCount; - } - - break; - - case "inactive": - var index = findIndex({id: data.id}); - - if( index >= 0 ) - { - if( !_.isUndefined(data.stats) ) - $scope.nodes[index].stats = data.stats; - - toastr['error']("Node "+ $scope.nodes[index].info.name +" went away!", "Node connection was lost!"); - - updateActiveNodes(); - } - - break; - - case "latency": - if( !_.isUndefined(data.id) && !_.isUndefined(data.latency) ) - { - var index = findIndex({id: data.id}); - - if( index >= 0 ) - { - var node = $scope.nodes[index]; - - if( !_.isUndefined(node) && !_.isUndefined(node.stats) && !_.isUndefined(node.stats.latency) && node.stats.latency !== data.latency ) - { - node.stats.latency = data.latency; - latencyFilter(node); - } - } - } - - break; - - case "client-ping": - socket.emit('client-pong', { - serverTime: data.serverTime, - clientTime: _.now() - }); - - break; - } - } - - function findIndex(search) - { - return _.findIndex($scope.nodes, search); - } - - function addNewNode(data) - { - var index = findIndex({id: data.id}); - - if( _.isUndefined(data.history) ) - { - data.history = new Array(40); - _.fill(data.history, -1); - } - - if( index < 0 ) - { - if( !_.isUndefined(data.stats) && _.isUndefined(data.stats.hashrate) ) - { - data.stats.hashrate = 0; - } - - data.pinned = false; - - $scope.nodes.push(data); - - return true; - } - - data.pinned = ( !_.isUndefined($scope.nodes[index].pinned) ? $scope.nodes[index].pinned : false); - - if( !_.isUndefined($scope.nodes[index].history) ) - { - data.history = $scope.nodes[index].history; - } - - $scope.nodes[index] = data; - - updateActiveNodes(); - - return false; - } - - function updateActiveNodes() - { - updateBestBlock(); - - $scope.nodesTotal = $scope.nodes.length; - - $scope.nodesActive = _.filter($scope.nodes, function (node) { - forkFilter(node); - return node.stats.active == true; - }).length; - } - - function updateBestBlock() - { - if( $scope.nodes.length ) - { - var chains = {}; - var maxScore = 0; - - _($scope.nodes) - .map(function (item) - { - maxScore += (item.trusted ? 50 : 1); - - if( _.isUndefined(chains[item.stats.block.number]) ) - chains[item.stats.block.number] = []; - - if( _.isUndefined(chains[item.stats.block.number][item.stats.block.fork]) ) - chains[item.stats.block.number][item.stats.block.fork] = { - fork: item.stats.block.fork, - count: 0, - trusted: 0, - score: 0 - }; - - if(item.stats.block.trusted) - chains[item.stats.block.number][item.stats.block.fork].trusted++; - else - chains[item.stats.block.number][item.stats.block.fork].count++; - - chains[item.stats.block.number][item.stats.block.fork].score = chains[item.stats.block.number][item.stats.block.fork].trusted * 50 + chains[item.stats.block.number][item.stats.block.fork].count; - }) - .value(); - - $scope.maxScore = maxScore; - $scope.chains = _.reduce(chains, function (result, item, key) - { - result[key] = _.max(item, 'score'); - return result; - }, {}); - - var bestBlock = _.max($scope.nodes, function (node) - { - // if( $scope.chains[node.stats.block.number].fork === node.stats.block.fork && $scope.chains[node.stats.block.number].score / $scope.maxScore >= 0.5 ) - // { - return parseInt(node.stats.block.number); - // } - - // return 0; - }).stats.block.number; - - if( bestBlock !== $scope.bestBlock ) - { - $scope.bestBlock = bestBlock; - $scope.bestStats = _.max($scope.nodes, function (node) { - return parseInt(node.stats.block.number); - }).stats; - - $scope.lastBlock = $scope.bestStats.block.arrived; - $scope.lastDifficulty = $scope.bestStats.block.difficulty; - } - } - } - - function forkFilter(node) - { - if( _.isUndefined(node.readable) ) - node.readable = {}; - - node.readable.forkClass = 'hidden'; - node.readable.forkMessage = ''; - - return true; - - if( $scope.chains[node.stats.block.number].fork === node.stats.block.fork && $scope.chains[node.stats.block.number].score / $scope.maxScore >= 0.5 ) - { - node.readable.forkClass = 'hidden'; - node.readable.forkMessage = ''; - - return true; - } - - if( $scope.chains[node.stats.block.number].fork !== node.stats.block.fork ) - { - node.readable.forkClass = 'text-danger'; - node.readable.forkMessage = 'Wrong chain.
This chain is a fork.'; - - return false; - } - - if( $scope.chains[node.stats.block.number].score / $scope.maxScore < 0.5) - { - node.readable.forkClass = 'text-warning'; - node.readable.forkMessage = 'May not be main chain.
Waiting for more confirmations.'; - - return false; - } - } - - function latencyFilter(node) - { - if( _.isUndefined(node.readable) ) - node.readable = {}; - - if( _.isUndefined(node.stats) ) { - node.readable.latencyClass = 'text-danger'; - node.readable.latency = 'offline'; - } - - if (node.stats.active === false) - { - node.readable.latencyClass = 'text-danger'; - node.readable.latency = 'offline'; - } - else - { - if (node.stats.latency <= 100) - node.readable.latencyClass = 'text-success'; - - if (node.stats.latency > 100 && node.stats.latency <= 1000) - node.readable.latencyClass = 'text-warning'; - - if (node.stats.latency > 1000) - node.readable.latencyClass = 'text-danger'; - - node.readable.latency = node.stats.latency + ' ms'; - } - } -}); \ No newline at end of file diff --git a/src-lite/js/directives.js b/src-lite/js/directives.js deleted file mode 100644 index c178f36..0000000 --- a/src-lite/js/directives.js +++ /dev/null @@ -1,8 +0,0 @@ -/* Directives */ - -angular.module('netStatsApp.directives', []) - .directive('appVersion', ['version', function (version) { - return function(scope, elm, attrs) { - elm.text(version); - }; -}]); \ No newline at end of file diff --git a/src-lite/js/filters.js b/src-lite/js/filters.js deleted file mode 100644 index f1d8ced..0000000 --- a/src-lite/js/filters.js +++ /dev/null @@ -1,596 +0,0 @@ - -/* Filters */ - -angular.module('netStatsApp.filters', []) -.filter('nodesActiveClass', function() { - return function(active, total) { - var ratio = active/total; - - if(ratio >= 0.9) - return 'text-success'; - - if(ratio >= 0.75) - return 'text-info'; - - if(ratio >= 0.5) - return 'text-warning'; - - return 'text-danger'; - }; -}) -.filter('nodePinClass', function() { - return function(pinned) { - if(pinned) - return 'icon-check-o'; - - return 'icon-loader'; - }; -}) -.filter('mainClass', function() { - return function(node, bestBlock) { - return mainClass(node, bestBlock); - }; -}) -.filter('peerClass', function() { - return function(peers, active) { - return peerClass(peers, active); - }; -}) -.filter('hashrateFilter', ['$sce', '$filter', function($sce, filter) { - return function(hashes, isMining) { - if( !isMining ) - return $sce.trustAsHtml(''); - - var result = hashes; - var units = ['', 'K', 'M', 'G', 'T', 'P']; - var unit = 'K'; - - for(var i = 1; result > 1000; i++) - { - result /= 1000; - unit = units[i]; - } - - return $sce.trustAsHtml('' + filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); - }; -}]) -.filter('totalDifficultyFilter', function() { - return function(hashes) { - var result = hashes; - var units = ['', 'K', 'M', 'G', 'T', 'P']; - var unit = ''; - - for(var i = 1; result > 1000; i++) - { - result /= 1000; - unit = units[i]; - } - - return result.toFixed(2) + ' ' + unit + 'H'; - }; -}) -.filter('nodeVersion', function($sce) { - return function(version) { - if(typeof version !== 'undefined') - { - var tmp = version.split('/'); - - tmp[0] = tmp[0].replace('Ethereum(++)', 'Eth'); - - if(tmp[0].indexOf('pyethapp') === 0) - { - tmp[0] = 'pyeth'; - } - - if(tmp[1][0] !== 'v' && tmp[1][2] !== '.') - { - tmp.splice(1,1); - } - - if(tmp[2] === 'Release'){ - tmp.splice(2,1); - } - - if(tmp[2].indexOf('Linux') === 0) - tmp[2] = 'linux'; - - if(tmp[2].indexOf('Darwin') === 0) - tmp[2] = 'darwin'; - - return $sce.trustAsHtml(tmp.join('/')); - } - - return ''; - }; -}) -.filter('blockClass', function() { - return function(current, best) { - if( ! current.active) - return 'text-gray'; - - return (best - current.block.number < 1 ? 'text-success' : (best - current.block.number === 1 ? 'text-warning' : (best - current.block.number > 1 && best - current.block.number < 4 ? 'text-orange' : 'text-danger'))); - }; -}) -.filter('gasPriceFilter', ['$filter', function(filter) { - var numberFilter = filter('number'); - return function(price) { - if(typeof price === 'undefined') - return "0 wei"; - - if(price.length < 4) - return numberFilter(price) + " wei"; - - if(price.length < 7) - return numberFilter(price/1000) + " kwei"; - - if(price.length < 10) - return numberFilter(price/1000000) + " mwei"; - - if(price.length < 13) - return numberFilter(price/1000000000) + " gwei"; - - if(price.length < 16) - return numberFilter(price/1000000000000) + " szabo"; - - if(price.length < 19) - return numberFilter(price.substr(0, price.length - 15)) + " finney"; - - return numberFilter(price.substr(0, price.length - 18)) + " ether"; - } -}]) -.filter('gasFilter', function() { - return function(gas) { - return (typeof gas !== 'undefined' ? parseInt(gas) : '?'); - } -}) -.filter('hashFilter', function() { - return function(hash) { - if(typeof hash === 'undefined') - return "?"; - - if(hash.substr(0,2) === '0x') - hash = hash.substr(2,64); - - return hash.substr(0, 8) + '...' + hash.substr(56, 8); - } -}) -.filter('timeClass', function() { - return function(timestamp, active) { - if( ! active) - return 'text-gray'; - - return timeClass(timestamp); - }; -}) -.filter('propagationTimeClass', function() { - return function(stats, bestBlock) { - if( ! stats.active) - return 'text-gray'; - - if(stats.block.number < bestBlock) - return 'text-gray'; - - if(stats.block.propagation == 0) - return 'text-info'; - - if(stats.block.propagation < 1000) - return 'text-success'; - - if(stats.block.propagation < 3000) - return 'text-warning'; - - if(stats.block.propagation < 7000) - return 'text-orange'; - - return 'text-danger' - }; -}) -.filter('propagationNodeAvgTimeClass', function() { - return function(stats, bestBlock) { - if( ! stats.active) - return 'text-gray'; - - if(stats.block.number < bestBlock) - return 'text-gray'; - - if(stats.propagationAvg == 0) - return 'text-info'; - - if(stats.propagationAvg < 1000) - return 'text-success'; - - if(stats.propagationAvg < 3000) - return 'text-warning'; - - if(stats.propagationAvg < 7000) - return 'text-orange'; - - return 'text-danger' - }; -}) -.filter('propagationAvgTimeClass', function() { - return function(propagationAvg, active) { - if( ! active) - return 'text-gray'; - - if(propagationAvg == 0) - return 'text-info'; - - if(propagationAvg < 1000) - return 'text-success'; - - if(propagationAvg < 3000) - return 'text-warning'; - - if(propagationAvg < 7000) - return 'text-orange'; - - return 'text-danger' - }; -}) -.filter('latencyFilter', function() { - return function(stats) { - if(stats.active === false) - return 'offline'; - else - return stats.latency + ' ms'; - } -}) -.filter('latencyClass', function() { - return function(stats) { - if(stats.active === false) - return 'text-danger'; - - if(stats.latency <= 100) - return 'text-success'; - - if(stats.latency <= 1000) - return 'text-warning'; - - return 'text-danger' - }; -}) -.filter('blockTimeFilter', function() { - return function(timestamp) { - if(timestamp === 0) - return '∞'; - - // var time = Math.floor((new Date()).getTime() / 1000); - var time = (new Date()).getTime(); - var diff = Math.floor((time - timestamp)/1000); - - if(diff < 60) - return Math.round(diff) + ' s ago'; - - return moment.duration(Math.round(diff), 's').humanize() + ' ago'; - }; -}) -.filter('networkHashrateFilter', ['$sce', '$filter', function($sce, filter) { - return function(hashes, isMining) { - if(hashes === null) - hashes = 0; - - var result = hashes; - var units = ['', 'K', 'M', 'G', 'T', 'P']; - var unit = 'K'; - - for(var i = 1; result > 1000; i++) - { - result /= 1000; - unit = units[i]; - } - - if( !isMining ) - return $sce.trustAsHtml(filter('number')(result.toFixed(1)) + ' ' + unit + 'H/s'); - - return $sce.trustAsHtml('? ' + unit + 'KH/s'); - }; -}]) -.filter('blockPropagationFilter', function() { - return function(ms, prefix) { - if(typeof prefix === 'undefined') - prefix = '+'; - - var result = 0; - - if(ms < 1000) { - return (ms === 0 ? "" : prefix) + ms + " ms"; - } - - if(ms < 1000*60) { - result = ms/1000; - return prefix + result.toFixed(1) + " s"; - } - - if(ms < 1000*60*60) { - result = ms/1000/60; - return prefix + Math.round(result) + " min"; - } - - if(ms < 1000*60*60*24) { - result = ms/1000/60/60; - return prefix + Math.round(result) + " h"; - } - - result = ms/1000/60/60/24; - return prefix + Math.round(result) + " days"; - }; -}) -.filter('blockPropagationAvgFilter', function() { - return function(stats, bestBlock) { - var ms = stats.propagationAvg; - - if(bestBlock - stats.block.number > 40) - return "∞"; - //ms = _.now() - stats.block.received; - - prefix = ''; - - var result = 0; - - if(ms < 1000) { - return (ms === 0 ? "" : prefix) + ms + " ms"; - } - - if(ms < 1000*60) { - result = ms/1000; - return prefix + result.toFixed(1) + " s"; - } - - if(ms < 1000*60*60) { - result = ms/1000/60; - return prefix + Math.round(result) + " min"; - } - - if(ms < 1000*60*60*24) { - result = ms/1000/60/60; - return prefix + Math.round(result) + " h"; - } - - result = ms/1000/60/60/24; - return prefix + Math.round(result) + " days"; - }; -}) -.filter('avgTimeFilter', function() { - return function(time) { - if(time < 60) - return Math.round(time) + ' s'; - - return moment.duration(Math.round(time), 's').humanize(); - }; -}) -.filter('avgTimeClass', function() { - return function(time) { - return blockTimeClass(time); - } -}) -.filter('upTimeFilter', function() { - return function(uptime) { - return Math.round(uptime) + '%'; - }; -}) -.filter('upTimeClass', function() { - return function(uptime, active) { - if( ! active ) - return 'text-gray'; - - if(uptime >= 90) - return 'text-success'; - - if(uptime >= 75) - return 'text-warning'; - - return 'text-danger'; - }; -}) -.filter('geoTooltip', function() { - return function(node) { - var tooltip = []; - var string = ''; - - if(node.info.node !== '' && typeof node.info.node !== 'undefined') { - var eth_version = node.info.node.split('/'); - - if(eth_version[1][0] !== 'v' && eth_version[1][2] !== '.') - { - eth_version.splice(1,1); - } - - string = "" + node.info.node + ""; - tooltip.push(string); - - string = "Version: " + (eth_version[1]) + ""; - tooltip.push(string); - } - - if(node.info.net !== '') { - string = "Network: " + (typeof node.info.net !== 'undefined' ? node.info.net : '-') + ""; - - tooltip.push(string); - } - - if(node.info.protocol !== '') { - string = "Protocol: " + (typeof node.info.protocol !== 'undefined' ? node.info.protocol : '-') + ""; - - tooltip.push(string); - } - - if(node.info.port !== '') { - string = "Port: " + (typeof node.info.port !== 'undefined' ? node.info.port : '30303') + ""; - - tooltip.push(string); - } - - if(node.info.api !== '') { - string = "Web3: " + node.info.api + ""; - - tooltip.push(string); - } - - if(node.info.client !== '') { - string = "API: " + (typeof node.info.client !== 'undefined' ? node.info.client : '<= 0.0.3') + ""; - - tooltip.push(string); - } - - if(node.info.os !== '') { - string = "OS: " + (typeof node.info.os !== 'undefined' ? node.info.os + ' ' + node.info.os_v : '?') + ""; - - tooltip.push(string); - } - - if(node.geo !== null) - { - string = "Location: "; - - if(node.geo.city !== '') - string += node.geo.city + ", "; - string += node.geo.country + ""; - - tooltip.push(string); - } - - if(node.info.contact !== '') { - string = "Contact: " + (typeof node.info.contact !== 'undefined' ? node.info.contact : '-') + ""; - - tooltip.push(string); - } - - return tooltip.join("
"); - }; -}) -.filter('bubbleClass', function() { - return function(node, bestBlock) { - return mainClass(node, bestBlock).replace('text-', ''); - }; -}) -.filter('minerNameFilter', function() { - return function(address, name) { - if(typeof name !== 'undefined' && name !== false && name.length > 0) - return name; - - return address.replace('0x', ''); - }; -}) -.filter('minerBlocksClass', function() { - return function(blocks, prefix) { - if(typeof prefix === 'undefined') - prefix = 'bg-'; - if(blocks <= 6) - return prefix + 'success'; - - if(blocks <= 12) - return prefix + 'info'; - - if(blocks <= 18) - return prefix + 'warning'; - - return prefix + 'danger'; - }; -}) -.filter('nodeClientClass', function() { - return function(info, current) { - if(typeof info === 'undefined' || typeof info.client === 'undefined' || typeof info.client === '') - return 'text-danger'; - - if(compareVersions(info.client, '<', current)) - return 'text-danger'; - - return 'hidden'; - }; -}) -.filter('consensusClass', function() { - return function(nodes, bestBlock) { - var status = 'text-success'; - var now = (new Date()).getTime(); - - for(var x = 0; x < nodes.length; x++) - { - if(nodes[x].stats.block.number === bestBlock.block.number && nodes[x].stats.block.hash !== bestBlock.block.hash) - return 'text-danger'; - - if((bestBlock.block.number - nodes[x].stats.block.number) > 1 && (now - bestBlock.block.received) >= 20*1000) - status = 'text-orange'; - - if((bestBlock.block.number - nodes[x].stats.block.number) === 1 && (now - bestBlock.block.received) >= 10*1000 && status !== 'orange') - status = 'text-warning'; - } - - return status; - }; -}) -.filter('consensusFilter', function() { - return function(nodes, bestBlock) { - var cnt = 0; - - for(var x = 0; x < nodes.length; x++) - { - if(nodes[x].stats.block.number === bestBlock.block.number && nodes[x].stats.block.hash === bestBlock.block.hash) - cnt++; - } - - return cnt + '/' + nodes.length; - }; -}); - -function compareVersions(v1, comparator, v2) -{ - comparator = comparator == '=' ? '==' : comparator; - - var v1parts = v1.split('.'), v2parts = v2.split('.'); - var maxLen = Math.max(v1parts.length, v2parts.length); - var part1, part2; - var cmp = 0; - - for(var i = 0; i < maxLen && !cmp; i++) - { - part1 = parseInt(v1parts[i], 10) || 0; - part2 = parseInt(v2parts[i], 10) || 0; - if(part1 < part2) - cmp = 1; - if(part1 > part2) - cmp = -1; - } - - return eval('0' + comparator + cmp); -} - -function mainClass(node, bestBlock) -{ - if( ! node.active) - return 'text-gray'; - - if(node.peers === 0) - return 'text-danger'; - - return peerClass(node.peers, node.active); -} - -function peerClass(peers, active) -{ - if( ! active) - return 'text-gray'; - - return (peers <= 1 ? 'text-danger' : (peers > 1 && peers < 4 ? 'text-warning' : 'text-success')); -} - -function timeClass(timestamp) -{ - var diff = ((new Date()).getTime() - timestamp)/1000; - - return blockTimeClass(diff); -} - -function blockTimeClass(diff) -{ - if(diff <= 13) - return 'text-success'; - - if(diff <= 20) - return 'text-warning'; - - if(diff <= 30) - return 'text-orange'; - - return 'text-danger' -} \ No newline at end of file diff --git a/src-lite/js/lib/angular.js b/src-lite/js/lib/angular.js deleted file mode 100644 index ccf3b4b..0000000 --- a/src-lite/js/lib/angular.js +++ /dev/null @@ -1,22154 +0,0 @@ -/** - * @license AngularJS v1.2.28 - * (c) 2010-2014 Google, Inc. http://angularjs.org - * License: MIT - */ -(function(window, document, undefined) {'use strict'; - -/** - * @description - * - * This object provides a utility for producing rich Error messages within - * Angular. It can be called as follows: - * - * var exampleMinErr = minErr('example'); - * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); - * - * The above creates an instance of minErr in the example namespace. The - * resulting error will have a namespaced error code of example.one. The - * resulting error will replace {0} with the value of foo, and {1} with the - * value of bar. The object is not restricted in the number of arguments it can - * take. - * - * If fewer arguments are specified than necessary for interpolation, the extra - * interpolation markers will be preserved in the final string. - * - * Since data will be parsed statically during a build step, some restrictions - * are applied with respect to how minErr instances are created and called. - * Instances should have names of the form namespaceMinErr for a minErr created - * using minErr('namespace') . Error codes, namespaces and template strings - * should all be static strings, not variables or general expressions. - * - * @param {string} module The namespace to use for the new minErr instance. - * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance - */ - -function minErr(module) { - return function () { - var code = arguments[0], - prefix = '[' + (module ? module + ':' : '') + code + '] ', - template = arguments[1], - templateArgs = arguments, - stringify = function (obj) { - if (typeof obj === 'function') { - return obj.toString().replace(/ \{[\s\S]*$/, ''); - } else if (typeof obj === 'undefined') { - return 'undefined'; - } else if (typeof obj !== 'string') { - return JSON.stringify(obj); - } - return obj; - }, - message, i; - - message = prefix + template.replace(/\{\d+\}/g, function (match) { - var index = +match.slice(1, -1), arg; - - if (index + 2 < templateArgs.length) { - arg = templateArgs[index + 2]; - if (typeof arg === 'function') { - return arg.toString().replace(/ ?\{[\s\S]*$/, ''); - } else if (typeof arg === 'undefined') { - return 'undefined'; - } else if (typeof arg !== 'string') { - return toJson(arg); - } - return arg; - } - return match; - }); - - message = message + '\nhttp://errors.angularjs.org/1.2.28/' + - (module ? module + '/' : '') + code; - for (i = 2; i < arguments.length; i++) { - message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + - encodeURIComponent(stringify(arguments[i])); - } - - return new Error(message); - }; -} - -/* We need to tell jshint what variables are being exported */ -/* global angular: true, - msie: true, - jqLite: true, - jQuery: true, - slice: true, - push: true, - toString: true, - ngMinErr: true, - angularModule: true, - nodeName_: true, - uid: true, - VALIDITY_STATE_PROPERTY: true, - - lowercase: true, - uppercase: true, - manualLowercase: true, - manualUppercase: true, - nodeName_: true, - isArrayLike: true, - forEach: true, - sortedKeys: true, - forEachSorted: true, - reverseParams: true, - nextUid: true, - setHashKey: true, - extend: true, - int: true, - inherit: true, - noop: true, - identity: true, - valueFn: true, - isUndefined: true, - isDefined: true, - isObject: true, - isString: true, - isNumber: true, - isDate: true, - isArray: true, - isFunction: true, - isRegExp: true, - isWindow: true, - isScope: true, - isFile: true, - isBlob: true, - isBoolean: true, - isPromiseLike: true, - trim: true, - isElement: true, - makeMap: true, - map: true, - size: true, - includes: true, - indexOf: true, - arrayRemove: true, - isLeafNode: true, - copy: true, - shallowCopy: true, - equals: true, - csp: true, - concat: true, - sliceArgs: true, - bind: true, - toJsonReplacer: true, - toJson: true, - fromJson: true, - toBoolean: true, - startingTag: true, - tryDecodeURIComponent: true, - parseKeyValue: true, - toKeyValue: true, - encodeUriSegment: true, - encodeUriQuery: true, - angularInit: true, - bootstrap: true, - snake_case: true, - bindJQuery: true, - assertArg: true, - assertArgFn: true, - assertNotHasOwnProperty: true, - getter: true, - getBlockElements: true, - hasOwnProperty: true, -*/ - -//////////////////////////////////// - -/** - * @ngdoc module - * @name ng - * @module ng - * @description - * - * # ng (core module) - * The ng module is loaded by default when an AngularJS application is started. The module itself - * contains the essential components for an AngularJS application to function. The table below - * lists a high level breakdown of each of the services/factories, filters, directives and testing - * components available within this core module. - * - *
- */ - -// The name of a form control's ValidityState property. -// This is used so that it's possible for internal tests to create mock ValidityStates. -var VALIDITY_STATE_PROPERTY = 'validity'; - -/** - * @ngdoc function - * @name angular.lowercase - * @module ng - * @kind function - * - * @description Converts the specified string to lowercase. - * @param {string} string String to be converted to lowercase. - * @returns {string} Lowercased string. - */ -var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; -var hasOwnProperty = Object.prototype.hasOwnProperty; - -/** - * @ngdoc function - * @name angular.uppercase - * @module ng - * @kind function - * - * @description Converts the specified string to uppercase. - * @param {string} string String to be converted to uppercase. - * @returns {string} Uppercased string. - */ -var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; - - -var manualLowercase = function(s) { - /* jshint bitwise: false */ - return isString(s) - ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) - : s; -}; -var manualUppercase = function(s) { - /* jshint bitwise: false */ - return isString(s) - ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) - : s; -}; - - -// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish -// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods -// with correct but slower alternatives. -if ('i' !== 'I'.toLowerCase()) { - lowercase = manualLowercase; - uppercase = manualUppercase; -} - - -var - msie, // holds major version number for IE, or NaN if UA is not IE. - jqLite, // delay binding since jQuery could be loaded after us. - jQuery, // delay binding - slice = [].slice, - push = [].push, - toString = Object.prototype.toString, - ngMinErr = minErr('ng'), - - /** @name angular */ - angular = window.angular || (window.angular = {}), - angularModule, - nodeName_, - uid = ['0', '0', '0']; - -/** - * IE 11 changed the format of the UserAgent string. - * See http://msdn.microsoft.com/en-us/library/ms537503.aspx - */ -msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); -if (isNaN(msie)) { - msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); -} - - -/** - * @private - * @param {*} obj - * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, - * String ...) - */ -function isArrayLike(obj) { - if (obj == null || isWindow(obj)) { - return false; - } - - var length = obj.length; - - if (obj.nodeType === 1 && length) { - return true; - } - - return isString(obj) || isArray(obj) || length === 0 || - typeof length === 'number' && length > 0 && (length - 1) in obj; -} - -/** - * @ngdoc function - * @name angular.forEach - * @module ng - * @kind function - * - * @description - * Invokes the `iterator` function once for each item in `obj` collection, which can be either an - * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value` - * is the value of an object property or an array element and `key` is the object property key or - * array element index. Specifying a `context` for the function is optional. - * - * It is worth noting that `.forEach` does not iterate over inherited properties because it filters - * using the `hasOwnProperty` method. - * - ```js - var values = {name: 'misko', gender: 'male'}; - var log = []; - angular.forEach(values, function(value, key) { - this.push(key + ': ' + value); - }, log); - expect(log).toEqual(['name: misko', 'gender: male']); - ``` - * - * @param {Object|Array} obj Object to iterate over. - * @param {Function} iterator Iterator function. - * @param {Object=} context Object to become context (`this`) for the iterator function. - * @returns {Object|Array} Reference to `obj`. - */ -function forEach(obj, iterator, context) { - var key; - if (obj) { - if (isFunction(obj)) { - for (key in obj) { - // Need to check if hasOwnProperty exists, - // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function - if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { - iterator.call(context, obj[key], key); - } - } - } else if (isArray(obj) || isArrayLike(obj)) { - for (key = 0; key < obj.length; key++) { - iterator.call(context, obj[key], key); - } - } else if (obj.forEach && obj.forEach !== forEach) { - obj.forEach(iterator, context); - } else { - for (key in obj) { - if (obj.hasOwnProperty(key)) { - iterator.call(context, obj[key], key); - } - } - } - } - return obj; -} - -function sortedKeys(obj) { - var keys = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - keys.push(key); - } - } - return keys.sort(); -} - -function forEachSorted(obj, iterator, context) { - var keys = sortedKeys(obj); - for ( var i = 0; i < keys.length; i++) { - iterator.call(context, obj[keys[i]], keys[i]); - } - return keys; -} - - -/** - * when using forEach the params are value, key, but it is often useful to have key, value. - * @param {function(string, *)} iteratorFn - * @returns {function(*, string)} - */ -function reverseParams(iteratorFn) { - return function(value, key) { iteratorFn(key, value); }; -} - -/** - * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric - * characters such as '012ABC'. The reason why we are not using simply a number counter is that - * the number string gets longer over time, and it can also overflow, where as the nextId - * will grow much slower, it is a string, and it will never overflow. - * - * @returns {string} an unique alpha-numeric string - */ -function nextUid() { - var index = uid.length; - var digit; - - while(index) { - index--; - digit = uid[index].charCodeAt(0); - if (digit == 57 /*'9'*/) { - uid[index] = 'A'; - return uid.join(''); - } - if (digit == 90 /*'Z'*/) { - uid[index] = '0'; - } else { - uid[index] = String.fromCharCode(digit + 1); - return uid.join(''); - } - } - uid.unshift('0'); - return uid.join(''); -} - - -/** - * Set or clear the hashkey for an object. - * @param obj object - * @param h the hashkey (!truthy to delete the hashkey) - */ -function setHashKey(obj, h) { - if (h) { - obj.$$hashKey = h; - } - else { - delete obj.$$hashKey; - } -} - -/** - * @ngdoc function - * @name angular.extend - * @module ng - * @kind function - * - * @description - * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) - * to `dst`. You can specify multiple `src` objects. - * - * @param {Object} dst Destination object. - * @param {...Object} src Source object(s). - * @returns {Object} Reference to `dst`. - */ -function extend(dst) { - var h = dst.$$hashKey; - forEach(arguments, function(obj) { - if (obj !== dst) { - forEach(obj, function(value, key) { - dst[key] = value; - }); - } - }); - - setHashKey(dst,h); - return dst; -} - -function int(str) { - return parseInt(str, 10); -} - - -function inherit(parent, extra) { - return extend(new (extend(function() {}, {prototype:parent}))(), extra); -} - -/** - * @ngdoc function - * @name angular.noop - * @module ng - * @kind function - * - * @description - * A function that performs no operations. This function can be useful when writing code in the - * functional style. - ```js - function foo(callback) { - var result = calculateResult(); - (callback || angular.noop)(result); - } - ``` - */ -function noop() {} -noop.$inject = []; - - -/** - * @ngdoc function - * @name angular.identity - * @module ng - * @kind function - * - * @description - * A function that returns its first argument. This function is useful when writing code in the - * functional style. - * - ```js - function transformer(transformationFn, value) { - return (transformationFn || angular.identity)(value); - }; - ``` - */ -function identity($) {return $;} -identity.$inject = []; - - -function valueFn(value) {return function() {return value;};} - -/** - * @ngdoc function - * @name angular.isUndefined - * @module ng - * @kind function - * - * @description - * Determines if a reference is undefined. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is undefined. - */ -function isUndefined(value){return typeof value === 'undefined';} - - -/** - * @ngdoc function - * @name angular.isDefined - * @module ng - * @kind function - * - * @description - * Determines if a reference is defined. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is defined. - */ -function isDefined(value){return typeof value !== 'undefined';} - - -/** - * @ngdoc function - * @name angular.isObject - * @module ng - * @kind function - * - * @description - * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not - * considered to be objects. Note that JavaScript arrays are objects. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is an `Object` but not `null`. - */ -function isObject(value){return value != null && typeof value === 'object';} - - -/** - * @ngdoc function - * @name angular.isString - * @module ng - * @kind function - * - * @description - * Determines if a reference is a `String`. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a `String`. - */ -function isString(value){return typeof value === 'string';} - - -/** - * @ngdoc function - * @name angular.isNumber - * @module ng - * @kind function - * - * @description - * Determines if a reference is a `Number`. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a `Number`. - */ -function isNumber(value){return typeof value === 'number';} - - -/** - * @ngdoc function - * @name angular.isDate - * @module ng - * @kind function - * - * @description - * Determines if a value is a date. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a `Date`. - */ -function isDate(value) { - return toString.call(value) === '[object Date]'; -} - - -/** - * @ngdoc function - * @name angular.isArray - * @module ng - * @kind function - * - * @description - * Determines if a reference is an `Array`. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is an `Array`. - */ -var isArray = (function() { - if (!isFunction(Array.isArray)) { - return function(value) { - return toString.call(value) === '[object Array]'; - }; - } - return Array.isArray; -})(); - -/** - * @ngdoc function - * @name angular.isFunction - * @module ng - * @kind function - * - * @description - * Determines if a reference is a `Function`. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a `Function`. - */ -function isFunction(value){return typeof value === 'function';} - - -/** - * Determines if a value is a regular expression object. - * - * @private - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a `RegExp`. - */ -function isRegExp(value) { - return toString.call(value) === '[object RegExp]'; -} - - -/** - * Checks if `obj` is a window object. - * - * @private - * @param {*} obj Object to check - * @returns {boolean} True if `obj` is a window obj. - */ -function isWindow(obj) { - return obj && obj.document && obj.location && obj.alert && obj.setInterval; -} - - -function isScope(obj) { - return obj && obj.$evalAsync && obj.$watch; -} - - -function isFile(obj) { - return toString.call(obj) === '[object File]'; -} - - -function isBlob(obj) { - return toString.call(obj) === '[object Blob]'; -} - - -function isBoolean(value) { - return typeof value === 'boolean'; -} - - -function isPromiseLike(obj) { - return obj && isFunction(obj.then); -} - - -var trim = (function() { - // native trim is way faster: http://jsperf.com/angular-trim-test - // but IE doesn't have it... :-( - // TODO: we should move this into IE/ES5 polyfill - if (!String.prototype.trim) { - return function(value) { - return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value; - }; - } - return function(value) { - return isString(value) ? value.trim() : value; - }; -})(); - - -/** - * @ngdoc function - * @name angular.isElement - * @module ng - * @kind function - * - * @description - * Determines if a reference is a DOM element (or wrapped jQuery element). - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). - */ -function isElement(node) { - return !!(node && - (node.nodeName // we are a direct element - || (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API -} - -/** - * @param str 'key1,key2,...' - * @returns {object} in the form of {key1:true, key2:true, ...} - */ -function makeMap(str) { - var obj = {}, items = str.split(","), i; - for ( i = 0; i < items.length; i++ ) - obj[ items[i] ] = true; - return obj; -} - - -if (msie < 9) { - nodeName_ = function(element) { - element = element.nodeName ? element : element[0]; - return (element.scopeName && element.scopeName != 'HTML') - ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName; - }; -} else { - nodeName_ = function(element) { - return element.nodeName ? element.nodeName : element[0].nodeName; - }; -} - - -function map(obj, iterator, context) { - var results = []; - forEach(obj, function(value, index, list) { - results.push(iterator.call(context, value, index, list)); - }); - return results; -} - - -/** - * @description - * Determines the number of elements in an array, the number of properties an object has, or - * the length of a string. - * - * Note: This function is used to augment the Object type in Angular expressions. See - * {@link angular.Object} for more information about Angular arrays. - * - * @param {Object|Array|string} obj Object, array, or string to inspect. - * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object - * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array. - */ -function size(obj, ownPropsOnly) { - var count = 0, key; - - if (isArray(obj) || isString(obj)) { - return obj.length; - } else if (isObject(obj)) { - for (key in obj) - if (!ownPropsOnly || obj.hasOwnProperty(key)) - count++; - } - - return count; -} - - -function includes(array, obj) { - return indexOf(array, obj) != -1; -} - -function indexOf(array, obj) { - if (array.indexOf) return array.indexOf(obj); - - for (var i = 0; i < array.length; i++) { - if (obj === array[i]) return i; - } - return -1; -} - -function arrayRemove(array, value) { - var index = indexOf(array, value); - if (index >=0) - array.splice(index, 1); - return value; -} - -function isLeafNode (node) { - if (node) { - switch (node.nodeName) { - case "OPTION": - case "PRE": - case "TITLE": - return true; - } - } - return false; -} - -/** - * @ngdoc function - * @name angular.copy - * @module ng - * @kind function - * - * @description - * Creates a deep copy of `source`, which should be an object or an array. - * - * * If no destination is supplied, a copy of the object or array is created. - * * If a destination is provided, all of its elements (for array) or properties (for objects) - * are deleted and then all elements/properties from the source are copied to it. - * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. - * * If `source` is identical to 'destination' an exception will be thrown. - * - * @param {*} source The source that will be used to make a copy. - * Can be any type, including primitives, `null`, and `undefined`. - * @param {(Object|Array)=} destination Destination into which the source is copied. If - * provided, must be of the same type as `source`. - * @returns {*} The copy or updated `destination`, if `destination` was specified. - * - * @example - - -
-
- Name:
- E-mail:
- Gender: male - female
- - -
-
form = {{user | json}}
-
master = {{master | json}}
-
- - -
-
- */ -function copy(source, destination, stackSource, stackDest) { - if (isWindow(source) || isScope(source)) { - throw ngMinErr('cpws', - "Can't copy! Making copies of Window or Scope instances is not supported."); - } - - if (!destination) { - destination = source; - if (source) { - if (isArray(source)) { - destination = copy(source, [], stackSource, stackDest); - } else if (isDate(source)) { - destination = new Date(source.getTime()); - } else if (isRegExp(source)) { - destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); - destination.lastIndex = source.lastIndex; - } else if (isObject(source)) { - destination = copy(source, {}, stackSource, stackDest); - } - } - } else { - if (source === destination) throw ngMinErr('cpi', - "Can't copy! Source and destination are identical."); - - stackSource = stackSource || []; - stackDest = stackDest || []; - - if (isObject(source)) { - var index = indexOf(stackSource, source); - if (index !== -1) return stackDest[index]; - - stackSource.push(source); - stackDest.push(destination); - } - - var result; - if (isArray(source)) { - destination.length = 0; - for ( var i = 0; i < source.length; i++) { - result = copy(source[i], null, stackSource, stackDest); - if (isObject(source[i])) { - stackSource.push(source[i]); - stackDest.push(result); - } - destination.push(result); - } - } else { - var h = destination.$$hashKey; - if (isArray(destination)) { - destination.length = 0; - } else { - forEach(destination, function(value, key) { - delete destination[key]; - }); - } - for ( var key in source) { - result = copy(source[key], null, stackSource, stackDest); - if (isObject(source[key])) { - stackSource.push(source[key]); - stackDest.push(result); - } - destination[key] = result; - } - setHashKey(destination,h); - } - - } - return destination; -} - -/** - * Creates a shallow copy of an object, an array or a primitive - */ -function shallowCopy(src, dst) { - if (isArray(src)) { - dst = dst || []; - - for ( var i = 0; i < src.length; i++) { - dst[i] = src[i]; - } - } else if (isObject(src)) { - dst = dst || {}; - - for (var key in src) { - if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { - dst[key] = src[key]; - } - } - } - - return dst || src; -} - - -/** - * @ngdoc function - * @name angular.equals - * @module ng - * @kind function - * - * @description - * Determines if two objects or two values are equivalent. Supports value types, regular - * expressions, arrays and objects. - * - * Two objects or values are considered equivalent if at least one of the following is true: - * - * * Both objects or values pass `===` comparison. - * * Both objects or values are of the same type and all of their properties are equal by - * comparing them with `angular.equals`. - * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) - * * Both values represent the same regular expression (In JavaScript, - * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual - * representation matches). - * - * During a property comparison, properties of `function` type and properties with names - * that begin with `$` are ignored. - * - * Scope and DOMWindow objects are being compared only by identify (`===`). - * - * @param {*} o1 Object or value to compare. - * @param {*} o2 Object or value to compare. - * @returns {boolean} True if arguments are equal. - */ -function equals(o1, o2) { - if (o1 === o2) return true; - if (o1 === null || o2 === null) return false; - if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN - var t1 = typeof o1, t2 = typeof o2, length, key, keySet; - if (t1 == t2) { - if (t1 == 'object') { - if (isArray(o1)) { - if (!isArray(o2)) return false; - if ((length = o1.length) == o2.length) { - for(key=0; key 2 ? sliceArgs(arguments, 2) : []; - if (isFunction(fn) && !(fn instanceof RegExp)) { - return curryArgs.length - ? function() { - return arguments.length - ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0))) - : fn.apply(self, curryArgs); - } - : function() { - return arguments.length - ? fn.apply(self, arguments) - : fn.call(self); - }; - } else { - // in IE, native methods are not functions so they cannot be bound (note: they don't need to be) - return fn; - } -} - - -function toJsonReplacer(key, value) { - var val = value; - - if (typeof key === 'string' && key.charAt(0) === '$') { - val = undefined; - } else if (isWindow(value)) { - val = '$WINDOW'; - } else if (value && document === value) { - val = '$DOCUMENT'; - } else if (isScope(value)) { - val = '$SCOPE'; - } - - return val; -} - - -/** - * @ngdoc function - * @name angular.toJson - * @module ng - * @kind function - * - * @description - * Serializes input into a JSON-formatted string. Properties with leading $ characters will be - * stripped since angular uses this notation internally. - * - * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. - * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace. - * @returns {string|undefined} JSON-ified string representing `obj`. - */ -function toJson(obj, pretty) { - if (typeof obj === 'undefined') return undefined; - return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null); -} - - -/** - * @ngdoc function - * @name angular.fromJson - * @module ng - * @kind function - * - * @description - * Deserializes a JSON string. - * - * @param {string} json JSON string to deserialize. - * @returns {Object|Array|string|number} Deserialized thingy. - */ -function fromJson(json) { - return isString(json) - ? JSON.parse(json) - : json; -} - - -function toBoolean(value) { - if (typeof value === 'function') { - value = true; - } else if (value && value.length !== 0) { - var v = lowercase("" + value); - value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]'); - } else { - value = false; - } - return value; -} - -/** - * @returns {string} Returns the string representation of the element. - */ -function startingTag(element) { - element = jqLite(element).clone(); - try { - // turns out IE does not let you set .html() on elements which - // are not allowed to have children. So we just ignore it. - element.empty(); - } catch(e) {} - // As Per DOM Standards - var TEXT_NODE = 3; - var elemHtml = jqLite('
').append(element).html(); - try { - return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) : - elemHtml. - match(/^(<[^>]+>)/)[1]. - replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); }); - } catch(e) { - return lowercase(elemHtml); - } - -} - - -///////////////////////////////////////////////// - -/** - * Tries to decode the URI component without throwing an exception. - * - * @private - * @param str value potential URI component to check. - * @returns {boolean} True if `value` can be decoded - * with the decodeURIComponent function. - */ -function tryDecodeURIComponent(value) { - try { - return decodeURIComponent(value); - } catch(e) { - // Ignore any invalid uri component - } -} - - -/** - * Parses an escaped url query string into key-value pairs. - * @returns {Object.} - */ -function parseKeyValue(/**string*/keyValue) { - var obj = {}, key_value, key; - forEach((keyValue || "").split('&'), function(keyValue) { - if ( keyValue ) { - key_value = keyValue.replace(/\+/g,'%20').split('='); - key = tryDecodeURIComponent(key_value[0]); - if ( isDefined(key) ) { - var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; - if (!hasOwnProperty.call(obj, key)) { - obj[key] = val; - } else if(isArray(obj[key])) { - obj[key].push(val); - } else { - obj[key] = [obj[key],val]; - } - } - } - }); - return obj; -} - -function toKeyValue(obj) { - var parts = []; - forEach(obj, function(value, key) { - if (isArray(value)) { - forEach(value, function(arrayValue) { - parts.push(encodeUriQuery(key, true) + - (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); - }); - } else { - parts.push(encodeUriQuery(key, true) + - (value === true ? '' : '=' + encodeUriQuery(value, true))); - } - }); - return parts.length ? parts.join('&') : ''; -} - - -/** - * We need our custom method because encodeURIComponent is too aggressive and doesn't follow - * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path - * segments: - * segment = *pchar - * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - * pct-encoded = "%" HEXDIG HEXDIG - * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - * / "*" / "+" / "," / ";" / "=" - */ -function encodeUriSegment(val) { - return encodeUriQuery(val, true). - replace(/%26/gi, '&'). - replace(/%3D/gi, '='). - replace(/%2B/gi, '+'); -} - - -/** - * This method is intended for encoding *key* or *value* parts of query component. We need a custom - * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be - * encoded per http://tools.ietf.org/html/rfc3986: - * query = *( pchar / "/" / "?" ) - * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - * pct-encoded = "%" HEXDIG HEXDIG - * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" - * / "*" / "+" / "," / ";" / "=" - */ -function encodeUriQuery(val, pctEncodeSpaces) { - return encodeURIComponent(val). - replace(/%40/gi, '@'). - replace(/%3A/gi, ':'). - replace(/%24/g, '$'). - replace(/%2C/gi, ','). - replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); -} - - -/** - * @ngdoc directive - * @name ngApp - * @module ng - * - * @element ANY - * @param {angular.Module} ngApp an optional application - * {@link angular.module module} name to load. - * - * @description - * - * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive - * designates the **root element** of the application and is typically placed near the root element - * of the page - e.g. on the `` or `` tags. - * - * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` - * found in the document will be used to define the root element to auto-bootstrap as an - * application. To run multiple applications in an HTML document you must manually bootstrap them using - * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other. - * - * You can specify an **AngularJS module** to be used as the root module for the application. This - * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and - * should contain the application code needed or have dependencies on other modules that will - * contain the code. See {@link angular.module} for more information. - * - * In the example below if the `ngApp` directive were not placed on the `html` element then the - * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` - * would not be resolved to `3`. - * - * `ngApp` is the easiest, and most common, way to bootstrap an application. - * - - -
- I can add: {{a}} + {{b}} = {{ a+b }} -
-
- - angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { - $scope.a = 1; - $scope.b = 2; - }); - -
- * - */ -function angularInit(element, bootstrap) { - var elements = [element], - appElement, - module, - names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'], - NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; - - function append(element) { - element && elements.push(element); - } - - forEach(names, function(name) { - names[name] = true; - append(document.getElementById(name)); - name = name.replace(':', '\\:'); - if (element.querySelectorAll) { - forEach(element.querySelectorAll('.' + name), append); - forEach(element.querySelectorAll('.' + name + '\\:'), append); - forEach(element.querySelectorAll('[' + name + ']'), append); - } - }); - - forEach(elements, function(element) { - if (!appElement) { - var className = ' ' + element.className + ' '; - var match = NG_APP_CLASS_REGEXP.exec(className); - if (match) { - appElement = element; - module = (match[2] || '').replace(/\s+/g, ','); - } else { - forEach(element.attributes, function(attr) { - if (!appElement && names[attr.name]) { - appElement = element; - module = attr.value; - } - }); - } - } - }); - if (appElement) { - bootstrap(appElement, module ? [module] : []); - } -} - -/** - * @ngdoc function - * @name angular.bootstrap - * @module ng - * @description - * Use this function to manually start up angular application. - * - * See: {@link guide/bootstrap Bootstrap} - * - * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually. - * They must use {@link ng.directive:ngApp ngApp}. - * - * Angular will detect if it has been loaded into the browser more than once and only allow the - * first loaded script to be bootstrapped and will report a warning to the browser console for - * each of the subsequent scripts. This prevents strange results in applications, where otherwise - * multiple instances of Angular try to work on the DOM. - * - * - * - * - *
- * - * - * - * - * - * - * - *
{{heading}}
{{fill}}
- *
- *
- * - * var app = angular.module('multi-bootstrap', []) - * - * .controller('BrokenTable', function($scope) { - * $scope.headings = ['One', 'Two', 'Three']; - * $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]]; - * }); - * - * - * it('should only insert one table cell for each item in $scope.fillings', function() { - * expect(element.all(by.css('td')).count()) - * .toBe(9); - * }); - * - *
- * - * @param {DOMElement} element DOM element which is the root of angular application. - * @param {Array=} modules an array of modules to load into the application. - * Each item in the array should be the name of a predefined module or a (DI annotated) - * function that will be invoked by the injector as a run block. - * See: {@link angular.module modules} - * @returns {auto.$injector} Returns the newly created injector for this app. - */ -function bootstrap(element, modules) { - var doBootstrap = function() { - element = jqLite(element); - - if (element.injector()) { - var tag = (element[0] === document) ? 'document' : startingTag(element); - //Encode angle brackets to prevent input from being sanitized to empty string #8683 - throw ngMinErr( - 'btstrpd', - "App Already Bootstrapped with this Element '{0}'", - tag.replace(//,'>')); - } - - modules = modules || []; - modules.unshift(['$provide', function($provide) { - $provide.value('$rootElement', element); - }]); - modules.unshift('ng'); - var injector = createInjector(modules); - injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate', - function(scope, element, compile, injector, animate) { - scope.$apply(function() { - element.data('$injector', injector); - compile(element)(scope); - }); - }] - ); - return injector; - }; - - var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; - - if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { - return doBootstrap(); - } - - window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); - angular.resumeBootstrap = function(extraModules) { - forEach(extraModules, function(module) { - modules.push(module); - }); - doBootstrap(); - }; -} - -var SNAKE_CASE_REGEXP = /[A-Z]/g; -function snake_case(name, separator) { - separator = separator || '_'; - return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { - return (pos ? separator : '') + letter.toLowerCase(); - }); -} - -function bindJQuery() { - // bind to jQuery if present; - jQuery = window.jQuery; - // Use jQuery if it exists with proper functionality, otherwise default to us. - // Angular 1.2+ requires jQuery 1.7.1+ for on()/off() support. - if (jQuery && jQuery.fn.on) { - jqLite = jQuery; - extend(jQuery.fn, { - scope: JQLitePrototype.scope, - isolateScope: JQLitePrototype.isolateScope, - controller: JQLitePrototype.controller, - injector: JQLitePrototype.injector, - inheritedData: JQLitePrototype.inheritedData - }); - // Method signature: - // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) - jqLitePatchJQueryRemove('remove', true, true, false); - jqLitePatchJQueryRemove('empty', false, false, false); - jqLitePatchJQueryRemove('html', false, false, true); - } else { - jqLite = JQLite; - } - angular.element = jqLite; -} - -/** - * throw error if the argument is falsy. - */ -function assertArg(arg, name, reason) { - if (!arg) { - throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); - } - return arg; -} - -function assertArgFn(arg, name, acceptArrayAnnotation) { - if (acceptArrayAnnotation && isArray(arg)) { - arg = arg[arg.length - 1]; - } - - assertArg(isFunction(arg), name, 'not a function, got ' + - (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); - return arg; -} - -/** - * throw error if the name given is hasOwnProperty - * @param {String} name the name to test - * @param {String} context the context in which the name is used, such as module or directive - */ -function assertNotHasOwnProperty(name, context) { - if (name === 'hasOwnProperty') { - throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); - } -} - -/** - * Return the value accessible from the object by path. Any undefined traversals are ignored - * @param {Object} obj starting object - * @param {String} path path to traverse - * @param {boolean} [bindFnToScope=true] - * @returns {Object} value as accessible by path - */ -//TODO(misko): this function needs to be removed -function getter(obj, path, bindFnToScope) { - if (!path) return obj; - var keys = path.split('.'); - var key; - var lastInstance = obj; - var len = keys.length; - - for (var i = 0; i < len; i++) { - key = keys[i]; - if (obj) { - obj = (lastInstance = obj)[key]; - } - } - if (!bindFnToScope && isFunction(obj)) { - return bind(lastInstance, obj); - } - return obj; -} - -/** - * Return the DOM siblings between the first and last node in the given array. - * @param {Array} array like object - * @returns {DOMElement} object containing the elements - */ -function getBlockElements(nodes) { - var startNode = nodes[0], - endNode = nodes[nodes.length - 1]; - if (startNode === endNode) { - return jqLite(startNode); - } - - var element = startNode; - var elements = [element]; - - do { - element = element.nextSibling; - if (!element) break; - elements.push(element); - } while (element !== endNode); - - return jqLite(elements); -} - -/** - * @ngdoc type - * @name angular.Module - * @module ng - * @description - * - * Interface for configuring angular {@link angular.module modules}. - */ - -function setupModuleLoader(window) { - - var $injectorMinErr = minErr('$injector'); - var ngMinErr = minErr('ng'); - - function ensure(obj, name, factory) { - return obj[name] || (obj[name] = factory()); - } - - var angular = ensure(window, 'angular', Object); - - // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap - angular.$$minErr = angular.$$minErr || minErr; - - return ensure(angular, 'module', function() { - /** @type {Object.} */ - var modules = {}; - - /** - * @ngdoc function - * @name angular.module - * @module ng - * @description - * - * The `angular.module` is a global place for creating, registering and retrieving Angular - * modules. - * All modules (angular core or 3rd party) that should be available to an application must be - * registered using this mechanism. - * - * When passed two or more arguments, a new module is created. If passed only one argument, an - * existing module (the name passed as the first argument to `module`) is retrieved. - * - * - * # Module - * - * A module is a collection of services, directives, controllers, filters, and configuration information. - * `angular.module` is used to configure the {@link auto.$injector $injector}. - * - * ```js - * // Create a new module - * var myModule = angular.module('myModule', []); - * - * // register a new service - * myModule.value('appName', 'MyCoolApp'); - * - * // configure existing services inside initialization blocks. - * myModule.config(['$locationProvider', function($locationProvider) { - * // Configure existing providers - * $locationProvider.hashPrefix('!'); - * }]); - * ``` - * - * Then you can create an injector and load your modules like this: - * - * ```js - * var injector = angular.injector(['ng', 'myModule']) - * ``` - * - * However it's more likely that you'll just use - * {@link ng.directive:ngApp ngApp} or - * {@link angular.bootstrap} to simplify this process for you. - * - * @param {!string} name The name of the module to create or retrieve. - * @param {!Array.=} requires If specified then new module is being created. If - * unspecified then the module is being retrieved for further configuration. - * @param {Function=} configFn Optional configuration function for the module. Same as - * {@link angular.Module#config Module#config()}. - * @returns {module} new module with the {@link angular.Module} api. - */ - return function module(name, requires, configFn) { - var assertNotHasOwnProperty = function(name, context) { - if (name === 'hasOwnProperty') { - throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); - } - }; - - assertNotHasOwnProperty(name, 'module'); - if (requires && modules.hasOwnProperty(name)) { - modules[name] = null; - } - return ensure(modules, name, function() { - if (!requires) { - throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + - "the module name or forgot to load it. If registering a module ensure that you " + - "specify the dependencies as the second argument.", name); - } - - /** @type {!Array.>} */ - var invokeQueue = []; - - /** @type {!Array.} */ - var runBlocks = []; - - var config = invokeLater('$injector', 'invoke'); - - /** @type {angular.Module} */ - var moduleInstance = { - // Private state - _invokeQueue: invokeQueue, - _runBlocks: runBlocks, - - /** - * @ngdoc property - * @name angular.Module#requires - * @module ng - * - * @description - * Holds the list of modules which the injector will load before the current module is - * loaded. - */ - requires: requires, - - /** - * @ngdoc property - * @name angular.Module#name - * @module ng - * - * @description - * Name of the module. - */ - name: name, - - - /** - * @ngdoc method - * @name angular.Module#provider - * @module ng - * @param {string} name service name - * @param {Function} providerType Construction function for creating new instance of the - * service. - * @description - * See {@link auto.$provide#provider $provide.provider()}. - */ - provider: invokeLater('$provide', 'provider'), - - /** - * @ngdoc method - * @name angular.Module#factory - * @module ng - * @param {string} name service name - * @param {Function} providerFunction Function for creating new instance of the service. - * @description - * See {@link auto.$provide#factory $provide.factory()}. - */ - factory: invokeLater('$provide', 'factory'), - - /** - * @ngdoc method - * @name angular.Module#service - * @module ng - * @param {string} name service name - * @param {Function} constructor A constructor function that will be instantiated. - * @description - * See {@link auto.$provide#service $provide.service()}. - */ - service: invokeLater('$provide', 'service'), - - /** - * @ngdoc method - * @name angular.Module#value - * @module ng - * @param {string} name service name - * @param {*} object Service instance object. - * @description - * See {@link auto.$provide#value $provide.value()}. - */ - value: invokeLater('$provide', 'value'), - - /** - * @ngdoc method - * @name angular.Module#constant - * @module ng - * @param {string} name constant name - * @param {*} object Constant value. - * @description - * Because the constant are fixed, they get applied before other provide methods. - * See {@link auto.$provide#constant $provide.constant()}. - */ - constant: invokeLater('$provide', 'constant', 'unshift'), - - /** - * @ngdoc method - * @name angular.Module#animation - * @module ng - * @param {string} name animation name - * @param {Function} animationFactory Factory function for creating new instance of an - * animation. - * @description - * - * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. - * - * - * Defines an animation hook that can be later used with - * {@link ngAnimate.$animate $animate} service and directives that use this service. - * - * ```js - * module.animation('.animation-name', function($inject1, $inject2) { - * return { - * eventName : function(element, done) { - * //code to run the animation - * //once complete, then run done() - * return function cancellationFunction(element) { - * //code to cancel the animation - * } - * } - * } - * }) - * ``` - * - * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and - * {@link ngAnimate ngAnimate module} for more information. - */ - animation: invokeLater('$animateProvider', 'register'), - - /** - * @ngdoc method - * @name angular.Module#filter - * @module ng - * @param {string} name Filter name. - * @param {Function} filterFactory Factory function for creating new instance of filter. - * @description - * See {@link ng.$filterProvider#register $filterProvider.register()}. - */ - filter: invokeLater('$filterProvider', 'register'), - - /** - * @ngdoc method - * @name angular.Module#controller - * @module ng - * @param {string|Object} name Controller name, or an object map of controllers where the - * keys are the names and the values are the constructors. - * @param {Function} constructor Controller constructor function. - * @description - * See {@link ng.$controllerProvider#register $controllerProvider.register()}. - */ - controller: invokeLater('$controllerProvider', 'register'), - - /** - * @ngdoc method - * @name angular.Module#directive - * @module ng - * @param {string|Object} name Directive name, or an object map of directives where the - * keys are the names and the values are the factories. - * @param {Function} directiveFactory Factory function for creating new instance of - * directives. - * @description - * See {@link ng.$compileProvider#directive $compileProvider.directive()}. - */ - directive: invokeLater('$compileProvider', 'directive'), - - /** - * @ngdoc method - * @name angular.Module#config - * @module ng - * @param {Function} configFn Execute this function on module load. Useful for service - * configuration. - * @description - * Use this method to register work which needs to be performed on module loading. - * For more about how to configure services, see - * {@link providers#providers_provider-recipe Provider Recipe}. - */ - config: config, - - /** - * @ngdoc method - * @name angular.Module#run - * @module ng - * @param {Function} initializationFn Execute this function after injector creation. - * Useful for application initialization. - * @description - * Use this method to register work which should be performed when the injector is done - * loading all modules. - */ - run: function(block) { - runBlocks.push(block); - return this; - } - }; - - if (configFn) { - config(configFn); - } - - return moduleInstance; - - /** - * @param {string} provider - * @param {string} method - * @param {String=} insertMethod - * @returns {angular.Module} - */ - function invokeLater(provider, method, insertMethod) { - return function() { - invokeQueue[insertMethod || 'push']([provider, method, arguments]); - return moduleInstance; - }; - } - }); - }; - }); - -} - -/* global angularModule: true, - version: true, - - $LocaleProvider, - $CompileProvider, - - htmlAnchorDirective, - inputDirective, - inputDirective, - formDirective, - scriptDirective, - selectDirective, - styleDirective, - optionDirective, - ngBindDirective, - ngBindHtmlDirective, - ngBindTemplateDirective, - ngClassDirective, - ngClassEvenDirective, - ngClassOddDirective, - ngCspDirective, - ngCloakDirective, - ngControllerDirective, - ngFormDirective, - ngHideDirective, - ngIfDirective, - ngIncludeDirective, - ngIncludeFillContentDirective, - ngInitDirective, - ngNonBindableDirective, - ngPluralizeDirective, - ngRepeatDirective, - ngShowDirective, - ngStyleDirective, - ngSwitchDirective, - ngSwitchWhenDirective, - ngSwitchDefaultDirective, - ngOptionsDirective, - ngTranscludeDirective, - ngModelDirective, - ngListDirective, - ngChangeDirective, - requiredDirective, - requiredDirective, - ngValueDirective, - ngAttributeAliasDirectives, - ngEventDirectives, - - $AnchorScrollProvider, - $AnimateProvider, - $BrowserProvider, - $CacheFactoryProvider, - $ControllerProvider, - $DocumentProvider, - $ExceptionHandlerProvider, - $FilterProvider, - $InterpolateProvider, - $IntervalProvider, - $HttpProvider, - $HttpBackendProvider, - $LocationProvider, - $LogProvider, - $ParseProvider, - $RootScopeProvider, - $QProvider, - $$SanitizeUriProvider, - $SceProvider, - $SceDelegateProvider, - $SnifferProvider, - $TemplateCacheProvider, - $TimeoutProvider, - $$RAFProvider, - $$AsyncCallbackProvider, - $WindowProvider -*/ - - -/** - * @ngdoc object - * @name angular.version - * @module ng - * @description - * An object that contains information about the current AngularJS version. This object has the - * following properties: - * - * - `full` – `{string}` – Full version string, such as "0.9.18". - * - `major` – `{number}` – Major version number, such as "0". - * - `minor` – `{number}` – Minor version number, such as "9". - * - `dot` – `{number}` – Dot version number, such as "18". - * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". - */ -var version = { - full: '1.2.28', // all of these placeholder strings will be replaced by grunt's - major: 1, // package task - minor: 2, - dot: 28, - codeName: 'finnish-disembarkation' -}; - - -function publishExternalAPI(angular){ - extend(angular, { - 'bootstrap': bootstrap, - 'copy': copy, - 'extend': extend, - 'equals': equals, - 'element': jqLite, - 'forEach': forEach, - 'injector': createInjector, - 'noop': noop, - 'bind': bind, - 'toJson': toJson, - 'fromJson': fromJson, - 'identity': identity, - 'isUndefined': isUndefined, - 'isDefined': isDefined, - 'isString': isString, - 'isFunction': isFunction, - 'isObject': isObject, - 'isNumber': isNumber, - 'isElement': isElement, - 'isArray': isArray, - 'version': version, - 'isDate': isDate, - 'lowercase': lowercase, - 'uppercase': uppercase, - 'callbacks': {counter: 0}, - '$$minErr': minErr, - '$$csp': csp - }); - - angularModule = setupModuleLoader(window); - try { - angularModule('ngLocale'); - } catch (e) { - angularModule('ngLocale', []).provider('$locale', $LocaleProvider); - } - - angularModule('ng', ['ngLocale'], ['$provide', - function ngModule($provide) { - // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. - $provide.provider({ - $$sanitizeUri: $$SanitizeUriProvider - }); - $provide.provider('$compile', $CompileProvider). - directive({ - a: htmlAnchorDirective, - input: inputDirective, - textarea: inputDirective, - form: formDirective, - script: scriptDirective, - select: selectDirective, - style: styleDirective, - option: optionDirective, - ngBind: ngBindDirective, - ngBindHtml: ngBindHtmlDirective, - ngBindTemplate: ngBindTemplateDirective, - ngClass: ngClassDirective, - ngClassEven: ngClassEvenDirective, - ngClassOdd: ngClassOddDirective, - ngCloak: ngCloakDirective, - ngController: ngControllerDirective, - ngForm: ngFormDirective, - ngHide: ngHideDirective, - ngIf: ngIfDirective, - ngInclude: ngIncludeDirective, - ngInit: ngInitDirective, - ngNonBindable: ngNonBindableDirective, - ngPluralize: ngPluralizeDirective, - ngRepeat: ngRepeatDirective, - ngShow: ngShowDirective, - ngStyle: ngStyleDirective, - ngSwitch: ngSwitchDirective, - ngSwitchWhen: ngSwitchWhenDirective, - ngSwitchDefault: ngSwitchDefaultDirective, - ngOptions: ngOptionsDirective, - ngTransclude: ngTranscludeDirective, - ngModel: ngModelDirective, - ngList: ngListDirective, - ngChange: ngChangeDirective, - required: requiredDirective, - ngRequired: requiredDirective, - ngValue: ngValueDirective - }). - directive({ - ngInclude: ngIncludeFillContentDirective - }). - directive(ngAttributeAliasDirectives). - directive(ngEventDirectives); - $provide.provider({ - $anchorScroll: $AnchorScrollProvider, - $animate: $AnimateProvider, - $browser: $BrowserProvider, - $cacheFactory: $CacheFactoryProvider, - $controller: $ControllerProvider, - $document: $DocumentProvider, - $exceptionHandler: $ExceptionHandlerProvider, - $filter: $FilterProvider, - $interpolate: $InterpolateProvider, - $interval: $IntervalProvider, - $http: $HttpProvider, - $httpBackend: $HttpBackendProvider, - $location: $LocationProvider, - $log: $LogProvider, - $parse: $ParseProvider, - $rootScope: $RootScopeProvider, - $q: $QProvider, - $sce: $SceProvider, - $sceDelegate: $SceDelegateProvider, - $sniffer: $SnifferProvider, - $templateCache: $TemplateCacheProvider, - $timeout: $TimeoutProvider, - $window: $WindowProvider, - $$rAF: $$RAFProvider, - $$asyncCallback : $$AsyncCallbackProvider - }); - } - ]); -} - -/* global JQLitePrototype: true, - addEventListenerFn: true, - removeEventListenerFn: true, - BOOLEAN_ATTR: true -*/ - -////////////////////////////////// -//JQLite -////////////////////////////////// - -/** - * @ngdoc function - * @name angular.element - * @module ng - * @kind function - * - * @description - * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. - * - * If jQuery is available, `angular.element` is an alias for the - * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` - * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." - * - *
jqLite is a tiny, API-compatible subset of jQuery that allows - * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most - * commonly needed functionality with the goal of having a very small footprint.
- * - * To use jQuery, simply load it before `DOMContentLoaded` event fired. - * - *
**Note:** all element references in Angular are always wrapped with jQuery or - * jqLite; they are never raw DOM references.
- * - * ## Angular's jqLite - * jqLite provides only the following jQuery methods: - * - * - [`addClass()`](http://api.jquery.com/addClass/) - * - [`after()`](http://api.jquery.com/after/) - * - [`append()`](http://api.jquery.com/append/) - * - [`attr()`](http://api.jquery.com/attr/) - * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData - * - [`children()`](http://api.jquery.com/children/) - Does not support selectors - * - [`clone()`](http://api.jquery.com/clone/) - * - [`contents()`](http://api.jquery.com/contents/) - * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()` - * - [`data()`](http://api.jquery.com/data/) - * - [`empty()`](http://api.jquery.com/empty/) - * - [`eq()`](http://api.jquery.com/eq/) - * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name - * - [`hasClass()`](http://api.jquery.com/hasClass/) - * - [`html()`](http://api.jquery.com/html/) - * - [`next()`](http://api.jquery.com/next/) - Does not support selectors - * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData - * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors - * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors - * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors - * - [`prepend()`](http://api.jquery.com/prepend/) - * - [`prop()`](http://api.jquery.com/prop/) - * - [`ready()`](http://api.jquery.com/ready/) - * - [`remove()`](http://api.jquery.com/remove/) - * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - * - [`removeClass()`](http://api.jquery.com/removeClass/) - * - [`removeData()`](http://api.jquery.com/removeData/) - * - [`replaceWith()`](http://api.jquery.com/replaceWith/) - * - [`text()`](http://api.jquery.com/text/) - * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers. - * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces - * - [`val()`](http://api.jquery.com/val/) - * - [`wrap()`](http://api.jquery.com/wrap/) - * - * ## jQuery/jqLite Extras - * Angular also provides the following additional methods and events to both jQuery and jqLite: - * - * ### Events - * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event - * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM - * element before it is removed. - * - * ### Methods - * - `controller(name)` - retrieves the controller of the current element or its parent. By default - * retrieves controller associated with the `ngController` directive. If `name` is provided as - * camelCase directive name, then the controller for this directive will be retrieved (e.g. - * `'ngModel'`). - * - `injector()` - retrieves the injector of the current element or its parent. - * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current - * element or its parent. - * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the - * current element. This getter should be used only on elements that contain a directive which starts a new isolate - * scope. Calling `scope()` on this element always returns the original non-isolate scope. - * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top - * parent element is reached. - * - * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. - * @returns {Object} jQuery object. - */ - -JQLite.expando = 'ng339'; - -var jqCache = JQLite.cache = {}, - jqId = 1, - addEventListenerFn = (window.document.addEventListener - ? function(element, type, fn) {element.addEventListener(type, fn, false);} - : function(element, type, fn) {element.attachEvent('on' + type, fn);}), - removeEventListenerFn = (window.document.removeEventListener - ? function(element, type, fn) {element.removeEventListener(type, fn, false); } - : function(element, type, fn) {element.detachEvent('on' + type, fn); }); - -/* - * !!! This is an undocumented "private" function !!! - */ -var jqData = JQLite._data = function(node) { - //jQuery always returns an object on cache miss - return this.cache[node[this.expando]] || {}; -}; - -function jqNextId() { return ++jqId; } - - -var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; -var MOZ_HACK_REGEXP = /^moz([A-Z])/; -var jqLiteMinErr = minErr('jqLite'); - -/** - * Converts snake_case to camelCase. - * Also there is special case for Moz prefix starting with upper case letter. - * @param name Name to normalize - */ -function camelCase(name) { - return name. - replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { - return offset ? letter.toUpperCase() : letter; - }). - replace(MOZ_HACK_REGEXP, 'Moz$1'); -} - -///////////////////////////////////////////// -// jQuery mutation patch -// -// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a -// $destroy event on all DOM nodes being removed. -// -///////////////////////////////////////////// - -function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) { - var originalJqFn = jQuery.fn[name]; - originalJqFn = originalJqFn.$original || originalJqFn; - removePatch.$original = originalJqFn; - jQuery.fn[name] = removePatch; - - function removePatch(param) { - // jshint -W040 - var list = filterElems && param ? [this.filter(param)] : [this], - fireEvent = dispatchThis, - set, setIndex, setLength, - element, childIndex, childLength, children; - - if (!getterIfNoArguments || param != null) { - while(list.length) { - set = list.shift(); - for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) { - element = jqLite(set[setIndex]); - if (fireEvent) { - element.triggerHandler('$destroy'); - } else { - fireEvent = !fireEvent; - } - for(childIndex = 0, childLength = (children = element.children()).length; - childIndex < childLength; - childIndex++) { - list.push(jQuery(children[childIndex])); - } - } - } - } - return originalJqFn.apply(this, arguments); - } -} - -var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; -var HTML_REGEXP = /<|&#?\w+;/; -var TAG_NAME_REGEXP = /<([\w:]+)/; -var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; - -var wrapMap = { - 'option': [1, ''], - - 'thead': [1, '', '
'], - 'col': [2, '', '
'], - 'tr': [2, '', '
'], - 'td': [3, '', '
'], - '_default': [0, "", ""] -}; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -function jqLiteIsTextNode(html) { - return !HTML_REGEXP.test(html); -} - -function jqLiteBuildFragment(html, context) { - var elem, tmp, tag, wrap, - fragment = context.createDocumentFragment(), - nodes = [], i, j, jj; - - if (jqLiteIsTextNode(html)) { - // Convert non-html into a text node - nodes.push(context.createTextNode(html)); - } else { - tmp = fragment.appendChild(context.createElement('div')); - // Convert html into DOM nodes - tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase(); - wrap = wrapMap[tag] || wrapMap._default; - tmp.innerHTML = '
 
' + - wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>") + wrap[2]; - tmp.removeChild(tmp.firstChild); - - // Descend through wrappers to the right content - i = wrap[0]; - while (i--) { - tmp = tmp.lastChild; - } - - for (j=0, jj=tmp.childNodes.length; j -1); -} - -function jqLiteRemoveClass(element, cssClasses) { - if (cssClasses && element.setAttribute) { - forEach(cssClasses.split(' '), function(cssClass) { - element.setAttribute('class', trim( - (" " + (element.getAttribute('class') || '') + " ") - .replace(/[\n\t]/g, " ") - .replace(" " + trim(cssClass) + " ", " ")) - ); - }); - } -} - -function jqLiteAddClass(element, cssClasses) { - if (cssClasses && element.setAttribute) { - var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') - .replace(/[\n\t]/g, " "); - - forEach(cssClasses.split(' '), function(cssClass) { - cssClass = trim(cssClass); - if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { - existingClasses += cssClass + ' '; - } - }); - - element.setAttribute('class', trim(existingClasses)); - } -} - -function jqLiteAddNodes(root, elements) { - if (elements) { - elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements)) - ? elements - : [ elements ]; - for(var i=0; i < elements.length; i++) { - root.push(elements[i]); - } - } -} - -function jqLiteController(element, name) { - return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller'); -} - -function jqLiteInheritedData(element, name, value) { - // if element is the document object work with the html element instead - // this makes $(document).scope() possible - if(element.nodeType == 9) { - element = element.documentElement; - } - var names = isArray(name) ? name : [name]; - - while (element) { - for (var i = 0, ii = names.length; i < ii; i++) { - if ((value = jqLite.data(element, names[i])) !== undefined) return value; - } - - // If dealing with a document fragment node with a host element, and no parent, use the host - // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM - // to lookup parent controllers. - element = element.parentNode || (element.nodeType === 11 && element.host); - } -} - -function jqLiteEmpty(element) { - for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) { - jqLiteDealoc(childNodes[i]); - } - while (element.firstChild) { - element.removeChild(element.firstChild); - } -} - -////////////////////////////////////////// -// Functions which are declared directly. -////////////////////////////////////////// -var JQLitePrototype = JQLite.prototype = { - ready: function(fn) { - var fired = false; - - function trigger() { - if (fired) return; - fired = true; - fn(); - } - - // check if document already is loaded - if (document.readyState === 'complete'){ - setTimeout(trigger); - } else { - this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9 - // we can not use jqLite since we are not done loading and jQuery could be loaded later. - // jshint -W064 - JQLite(window).on('load', trigger); // fallback to window.onload for others - // jshint +W064 - } - }, - toString: function() { - var value = []; - forEach(this, function(e){ value.push('' + e);}); - return '[' + value.join(', ') + ']'; - }, - - eq: function(index) { - return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); - }, - - length: 0, - push: push, - sort: [].sort, - splice: [].splice -}; - -////////////////////////////////////////// -// Functions iterating getter/setters. -// these functions return self on setter and -// value on get. -////////////////////////////////////////// -var BOOLEAN_ATTR = {}; -forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { - BOOLEAN_ATTR[lowercase(value)] = value; -}); -var BOOLEAN_ELEMENTS = {}; -forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { - BOOLEAN_ELEMENTS[uppercase(value)] = true; -}); - -function getBooleanAttrName(element, name) { - // check dom last since we will most likely fail on name - var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; - - // booleanAttr is here twice to minimize DOM access - return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr; -} - -forEach({ - data: jqLiteData, - removeData: jqLiteRemoveData -}, function(fn, name) { - JQLite[name] = fn; -}); - -forEach({ - data: jqLiteData, - inheritedData: jqLiteInheritedData, - - scope: function(element) { - // Can't use jqLiteData here directly so we stay compatible with jQuery! - return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); - }, - - isolateScope: function(element) { - // Can't use jqLiteData here directly so we stay compatible with jQuery! - return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate'); - }, - - controller: jqLiteController, - - injector: function(element) { - return jqLiteInheritedData(element, '$injector'); - }, - - removeAttr: function(element,name) { - element.removeAttribute(name); - }, - - hasClass: jqLiteHasClass, - - css: function(element, name, value) { - name = camelCase(name); - - if (isDefined(value)) { - element.style[name] = value; - } else { - var val; - - if (msie <= 8) { - // this is some IE specific weirdness that jQuery 1.6.4 does not sure why - val = element.currentStyle && element.currentStyle[name]; - if (val === '') val = 'auto'; - } - - val = val || element.style[name]; - - if (msie <= 8) { - // jquery weirdness :-/ - val = (val === '') ? undefined : val; - } - - return val; - } - }, - - attr: function(element, name, value){ - var lowercasedName = lowercase(name); - if (BOOLEAN_ATTR[lowercasedName]) { - if (isDefined(value)) { - if (!!value) { - element[name] = true; - element.setAttribute(name, lowercasedName); - } else { - element[name] = false; - element.removeAttribute(lowercasedName); - } - } else { - return (element[name] || - (element.attributes.getNamedItem(name)|| noop).specified) - ? lowercasedName - : undefined; - } - } else if (isDefined(value)) { - element.setAttribute(name, value); - } else if (element.getAttribute) { - // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code - // some elements (e.g. Document) don't have get attribute, so return undefined - var ret = element.getAttribute(name, 2); - // normalize non-existing attributes to undefined (as jQuery) - return ret === null ? undefined : ret; - } - }, - - prop: function(element, name, value) { - if (isDefined(value)) { - element[name] = value; - } else { - return element[name]; - } - }, - - text: (function() { - var NODE_TYPE_TEXT_PROPERTY = []; - if (msie < 9) { - NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/ - NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/ - } else { - NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/ - NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/ - } - getText.$dv = ''; - return getText; - - function getText(element, value) { - var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]; - if (isUndefined(value)) { - return textProp ? element[textProp] : ''; - } - element[textProp] = value; - } - })(), - - val: function(element, value) { - if (isUndefined(value)) { - if (nodeName_(element) === 'SELECT' && element.multiple) { - var result = []; - forEach(element.options, function (option) { - if (option.selected) { - result.push(option.value || option.text); - } - }); - return result.length === 0 ? null : result; - } - return element.value; - } - element.value = value; - }, - - html: function(element, value) { - if (isUndefined(value)) { - return element.innerHTML; - } - for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) { - jqLiteDealoc(childNodes[i]); - } - element.innerHTML = value; - }, - - empty: jqLiteEmpty -}, function(fn, name){ - /** - * Properties: writes return selection, reads return first value - */ - JQLite.prototype[name] = function(arg1, arg2) { - var i, key; - var nodeCount = this.length; - - // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it - // in a way that survives minification. - // jqLiteEmpty takes no arguments but is a setter. - if (fn !== jqLiteEmpty && - (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) { - if (isObject(arg1)) { - - // we are a write, but the object properties are the key/values - for (i = 0; i < nodeCount; i++) { - if (fn === jqLiteData) { - // data() takes the whole object in jQuery - fn(this[i], arg1); - } else { - for (key in arg1) { - fn(this[i], key, arg1[key]); - } - } - } - // return self for chaining - return this; - } else { - // we are a read, so read the first child. - // TODO: do we still need this? - var value = fn.$dv; - // Only if we have $dv do we iterate over all, otherwise it is just the first element. - var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount; - for (var j = 0; j < jj; j++) { - var nodeValue = fn(this[j], arg1, arg2); - value = value ? value + nodeValue : nodeValue; - } - return value; - } - } else { - // we are a write, so apply to all children - for (i = 0; i < nodeCount; i++) { - fn(this[i], arg1, arg2); - } - // return self for chaining - return this; - } - }; -}); - -function createEventHandler(element, events) { - var eventHandler = function (event, type) { - if (!event.preventDefault) { - event.preventDefault = function() { - event.returnValue = false; //ie - }; - } - - if (!event.stopPropagation) { - event.stopPropagation = function() { - event.cancelBubble = true; //ie - }; - } - - if (!event.target) { - event.target = event.srcElement || document; - } - - if (isUndefined(event.defaultPrevented)) { - var prevent = event.preventDefault; - event.preventDefault = function() { - event.defaultPrevented = true; - prevent.call(event); - }; - event.defaultPrevented = false; - } - - event.isDefaultPrevented = function() { - return event.defaultPrevented || event.returnValue === false; - }; - - // Copy event handlers in case event handlers array is modified during execution. - var eventHandlersCopy = shallowCopy(events[type || event.type] || []); - - forEach(eventHandlersCopy, function(fn) { - fn.call(element, event); - }); - - // Remove monkey-patched methods (IE), - // as they would cause memory leaks in IE8. - if (msie <= 8) { - // IE7/8 does not allow to delete property on native object - event.preventDefault = null; - event.stopPropagation = null; - event.isDefaultPrevented = null; - } else { - // It shouldn't affect normal browsers (native methods are defined on prototype). - delete event.preventDefault; - delete event.stopPropagation; - delete event.isDefaultPrevented; - } - }; - eventHandler.elem = element; - return eventHandler; -} - -////////////////////////////////////////// -// Functions iterating traversal. -// These functions chain results into a single -// selector. -////////////////////////////////////////// -forEach({ - removeData: jqLiteRemoveData, - - dealoc: jqLiteDealoc, - - on: function onFn(element, type, fn, unsupported){ - if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); - - var events = jqLiteExpandoStore(element, 'events'), - handle = jqLiteExpandoStore(element, 'handle'); - - if (!events) jqLiteExpandoStore(element, 'events', events = {}); - if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events)); - - forEach(type.split(' '), function(type){ - var eventFns = events[type]; - - if (!eventFns) { - if (type == 'mouseenter' || type == 'mouseleave') { - var contains = document.body.contains || document.body.compareDocumentPosition ? - function( a, b ) { - // jshint bitwise: false - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - events[type] = []; - - // Refer to jQuery's implementation of mouseenter & mouseleave - // Read about mouseenter and mouseleave: - // http://www.quirksmode.org/js/events_mouse.html#link8 - var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}; - - onFn(element, eventmap[type], function(event) { - var target = this, related = event.relatedTarget; - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !contains(target, related)) ){ - handle(event, type); - } - }); - - } else { - addEventListenerFn(element, type, handle); - events[type] = []; - } - eventFns = events[type]; - } - eventFns.push(fn); - }); - }, - - off: jqLiteOff, - - one: function(element, type, fn) { - element = jqLite(element); - - //add the listener twice so that when it is called - //you can remove the original function and still be - //able to call element.off(ev, fn) normally - element.on(type, function onFn() { - element.off(type, fn); - element.off(type, onFn); - }); - element.on(type, fn); - }, - - replaceWith: function(element, replaceNode) { - var index, parent = element.parentNode; - jqLiteDealoc(element); - forEach(new JQLite(replaceNode), function(node){ - if (index) { - parent.insertBefore(node, index.nextSibling); - } else { - parent.replaceChild(node, element); - } - index = node; - }); - }, - - children: function(element) { - var children = []; - forEach(element.childNodes, function(element){ - if (element.nodeType === 1) - children.push(element); - }); - return children; - }, - - contents: function(element) { - return element.contentDocument || element.childNodes || []; - }, - - append: function(element, node) { - forEach(new JQLite(node), function(child){ - if (element.nodeType === 1 || element.nodeType === 11) { - element.appendChild(child); - } - }); - }, - - prepend: function(element, node) { - if (element.nodeType === 1) { - var index = element.firstChild; - forEach(new JQLite(node), function(child){ - element.insertBefore(child, index); - }); - } - }, - - wrap: function(element, wrapNode) { - wrapNode = jqLite(wrapNode)[0]; - var parent = element.parentNode; - if (parent) { - parent.replaceChild(wrapNode, element); - } - wrapNode.appendChild(element); - }, - - remove: function(element) { - jqLiteDealoc(element); - var parent = element.parentNode; - if (parent) parent.removeChild(element); - }, - - after: function(element, newElement) { - var index = element, parent = element.parentNode; - forEach(new JQLite(newElement), function(node){ - parent.insertBefore(node, index.nextSibling); - index = node; - }); - }, - - addClass: jqLiteAddClass, - removeClass: jqLiteRemoveClass, - - toggleClass: function(element, selector, condition) { - if (selector) { - forEach(selector.split(' '), function(className){ - var classCondition = condition; - if (isUndefined(classCondition)) { - classCondition = !jqLiteHasClass(element, className); - } - (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); - }); - } - }, - - parent: function(element) { - var parent = element.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - - next: function(element) { - if (element.nextElementSibling) { - return element.nextElementSibling; - } - - // IE8 doesn't have nextElementSibling - var elm = element.nextSibling; - while (elm != null && elm.nodeType !== 1) { - elm = elm.nextSibling; - } - return elm; - }, - - find: function(element, selector) { - if (element.getElementsByTagName) { - return element.getElementsByTagName(selector); - } else { - return []; - } - }, - - clone: jqLiteClone, - - triggerHandler: function(element, event, extraParameters) { - - var dummyEvent, eventFnsCopy, handlerArgs; - var eventName = event.type || event; - var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName]; - - if (eventFns) { - - // Create a dummy event to pass to the handlers - dummyEvent = { - preventDefault: function() { this.defaultPrevented = true; }, - isDefaultPrevented: function() { return this.defaultPrevented === true; }, - stopPropagation: noop, - type: eventName, - target: element - }; - - // If a custom event was provided then extend our dummy event with it - if (event.type) { - dummyEvent = extend(dummyEvent, event); - } - - // Copy event handlers in case event handlers array is modified during execution. - eventFnsCopy = shallowCopy(eventFns); - handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; - - forEach(eventFnsCopy, function(fn) { - fn.apply(element, handlerArgs); - }); - - } - } -}, function(fn, name){ - /** - * chaining functions - */ - JQLite.prototype[name] = function(arg1, arg2, arg3) { - var value; - for(var i=0; i < this.length; i++) { - if (isUndefined(value)) { - value = fn(this[i], arg1, arg2, arg3); - if (isDefined(value)) { - // any function which returns a value needs to be wrapped - value = jqLite(value); - } - } else { - jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); - } - } - return isDefined(value) ? value : this; - }; - - // bind legacy bind/unbind to on/off - JQLite.prototype.bind = JQLite.prototype.on; - JQLite.prototype.unbind = JQLite.prototype.off; -}); - -/** - * Computes a hash of an 'obj'. - * Hash of a: - * string is string - * number is number as string - * object is either result of calling $$hashKey function on the object or uniquely generated id, - * that is also assigned to the $$hashKey property of the object. - * - * @param obj - * @returns {string} hash string such that the same input will have the same hash string. - * The resulting string key is in 'type:hashKey' format. - */ -function hashKey(obj, nextUidFn) { - var objType = typeof obj, - key; - - if (objType == 'function' || (objType == 'object' && obj !== null)) { - if (typeof (key = obj.$$hashKey) == 'function') { - // must invoke on object to keep the right this - key = obj.$$hashKey(); - } else if (key === undefined) { - key = obj.$$hashKey = (nextUidFn || nextUid)(); - } - } else { - key = obj; - } - - return objType + ':' + key; -} - -/** - * HashMap which can use objects as keys - */ -function HashMap(array, isolatedUid) { - if (isolatedUid) { - var uid = 0; - this.nextUid = function() { - return ++uid; - }; - } - forEach(array, this.put, this); -} -HashMap.prototype = { - /** - * Store key value pair - * @param key key to store can be any type - * @param value value to store can be any type - */ - put: function(key, value) { - this[hashKey(key, this.nextUid)] = value; - }, - - /** - * @param key - * @returns {Object} the value for the key - */ - get: function(key) { - return this[hashKey(key, this.nextUid)]; - }, - - /** - * Remove the key/value pair - * @param key - */ - remove: function(key) { - var value = this[key = hashKey(key, this.nextUid)]; - delete this[key]; - return value; - } -}; - -/** - * @ngdoc function - * @module ng - * @name angular.injector - * @kind function - * - * @description - * Creates an injector object that can be used for retrieving services as well as for - * dependency injection (see {@link guide/di dependency injection}). - * - - * @param {Array.} modules A list of module functions or their aliases. See - * {@link angular.module}. The `ng` module must be explicitly added. - * @returns {injector} Injector object. See {@link auto.$injector $injector}. - * - * @example - * Typical usage - * ```js - * // create an injector - * var $injector = angular.injector(['ng']); - * - * // use the injector to kick off your application - * // use the type inference to auto inject arguments, or use implicit injection - * $injector.invoke(function($rootScope, $compile, $document){ - * $compile($document)($rootScope); - * $rootScope.$digest(); - * }); - * ``` - * - * Sometimes you want to get access to the injector of a currently running Angular app - * from outside Angular. Perhaps, you want to inject and compile some markup after the - * application has been bootstrapped. You can do this using the extra `injector()` added - * to JQuery/jqLite elements. See {@link angular.element}. - * - * *This is fairly rare but could be the case if a third party library is injecting the - * markup.* - * - * In the following example a new block of HTML containing a `ng-controller` - * directive is added to the end of the document body by JQuery. We then compile and link - * it into the current AngularJS scope. - * - * ```js - * var $div = $('
{{content.label}}
'); - * $(document.body).append($div); - * - * angular.element(document).injector().invoke(function($compile) { - * var scope = angular.element($div).scope(); - * $compile($div)(scope); - * }); - * ``` - */ - - -/** - * @ngdoc module - * @name auto - * @description - * - * Implicit module which gets automatically added to each {@link auto.$injector $injector}. - */ - -var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; -var FN_ARG_SPLIT = /,/; -var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; -var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; -var $injectorMinErr = minErr('$injector'); -function annotate(fn) { - var $inject, - fnText, - argDecl, - last; - - if (typeof fn === 'function') { - if (!($inject = fn.$inject)) { - $inject = []; - if (fn.length) { - fnText = fn.toString().replace(STRIP_COMMENTS, ''); - argDecl = fnText.match(FN_ARGS); - forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){ - arg.replace(FN_ARG, function(all, underscore, name){ - $inject.push(name); - }); - }); - } - fn.$inject = $inject; - } - } else if (isArray(fn)) { - last = fn.length - 1; - assertArgFn(fn[last], 'fn'); - $inject = fn.slice(0, last); - } else { - assertArgFn(fn, 'fn', true); - } - return $inject; -} - -/////////////////////////////////////// - -/** - * @ngdoc service - * @name $injector - * - * @description - * - * `$injector` is used to retrieve object instances as defined by - * {@link auto.$provide provider}, instantiate types, invoke methods, - * and load modules. - * - * The following always holds true: - * - * ```js - * var $injector = angular.injector(); - * expect($injector.get('$injector')).toBe($injector); - * expect($injector.invoke(function($injector){ - * return $injector; - * })).toBe($injector); - * ``` - * - * # Injection Function Annotation - * - * JavaScript does not have annotations, and annotations are needed for dependency injection. The - * following are all valid ways of annotating function with injection arguments and are equivalent. - * - * ```js - * // inferred (only works if code not minified/obfuscated) - * $injector.invoke(function(serviceA){}); - * - * // annotated - * function explicit(serviceA) {}; - * explicit.$inject = ['serviceA']; - * $injector.invoke(explicit); - * - * // inline - * $injector.invoke(['serviceA', function(serviceA){}]); - * ``` - * - * ## Inference - * - * In JavaScript calling `toString()` on a function returns the function definition. The definition - * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with - * minification, and obfuscation tools since these tools change the argument names. - * - * ## `$inject` Annotation - * By adding an `$inject` property onto a function the injection parameters can be specified. - * - * ## Inline - * As an array of injection names, where the last item in the array is the function to call. - */ - -/** - * @ngdoc method - * @name $injector#get - * - * @description - * Return an instance of the service. - * - * @param {string} name The name of the instance to retrieve. - * @return {*} The instance. - */ - -/** - * @ngdoc method - * @name $injector#invoke - * - * @description - * Invoke the method and supply the method arguments from the `$injector`. - * - * @param {!Function} fn The function to invoke. Function parameters are injected according to the - * {@link guide/di $inject Annotation} rules. - * @param {Object=} self The `this` for the invoked method. - * @param {Object=} locals Optional object. If preset then any argument names are read from this - * object first, before the `$injector` is consulted. - * @returns {*} the value returned by the invoked `fn` function. - */ - -/** - * @ngdoc method - * @name $injector#has - * - * @description - * Allows the user to query if the particular service exists. - * - * @param {string} name Name of the service to query. - * @returns {boolean} `true` if injector has given service. - */ - -/** - * @ngdoc method - * @name $injector#instantiate - * @description - * Create a new instance of JS type. The method takes a constructor function, invokes the new - * operator, and supplies all of the arguments to the constructor function as specified by the - * constructor annotation. - * - * @param {Function} Type Annotated constructor function. - * @param {Object=} locals Optional object. If preset then any argument names are read from this - * object first, before the `$injector` is consulted. - * @returns {Object} new instance of `Type`. - */ - -/** - * @ngdoc method - * @name $injector#annotate - * - * @description - * Returns an array of service names which the function is requesting for injection. This API is - * used by the injector to determine which services need to be injected into the function when the - * function is invoked. There are three ways in which the function can be annotated with the needed - * dependencies. - * - * # Argument names - * - * The simplest form is to extract the dependencies from the arguments of the function. This is done - * by converting the function into a string using `toString()` method and extracting the argument - * names. - * ```js - * // Given - * function MyController($scope, $route) { - * // ... - * } - * - * // Then - * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); - * ``` - * - * This method does not work with code minification / obfuscation. For this reason the following - * annotation strategies are supported. - * - * # The `$inject` property - * - * If a function has an `$inject` property and its value is an array of strings, then the strings - * represent names of services to be injected into the function. - * ```js - * // Given - * var MyController = function(obfuscatedScope, obfuscatedRoute) { - * // ... - * } - * // Define function dependencies - * MyController['$inject'] = ['$scope', '$route']; - * - * // Then - * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); - * ``` - * - * # The array notation - * - * It is often desirable to inline Injected functions and that's when setting the `$inject` property - * is very inconvenient. In these situations using the array notation to specify the dependencies in - * a way that survives minification is a better choice: - * - * ```js - * // We wish to write this (not minification / obfuscation safe) - * injector.invoke(function($compile, $rootScope) { - * // ... - * }); - * - * // We are forced to write break inlining - * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { - * // ... - * }; - * tmpFn.$inject = ['$compile', '$rootScope']; - * injector.invoke(tmpFn); - * - * // To better support inline function the inline annotation is supported - * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { - * // ... - * }]); - * - * // Therefore - * expect(injector.annotate( - * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) - * ).toEqual(['$compile', '$rootScope']); - * ``` - * - * @param {Function|Array.} fn Function for which dependent service names need to - * be retrieved as described above. - * - * @returns {Array.} The names of the services which the function requires. - */ - - - - -/** - * @ngdoc service - * @name $provide - * - * @description - * - * The {@link auto.$provide $provide} service has a number of methods for registering components - * with the {@link auto.$injector $injector}. Many of these functions are also exposed on - * {@link angular.Module}. - * - * An Angular **service** is a singleton object created by a **service factory**. These **service - * factories** are functions which, in turn, are created by a **service provider**. - * The **service providers** are constructor functions. When instantiated they must contain a - * property called `$get`, which holds the **service factory** function. - * - * When you request a service, the {@link auto.$injector $injector} is responsible for finding the - * correct **service provider**, instantiating it and then calling its `$get` **service factory** - * function to get the instance of the **service**. - * - * Often services have no configuration options and there is no need to add methods to the service - * provider. The provider will be no more than a constructor function with a `$get` property. For - * these cases the {@link auto.$provide $provide} service has additional helper methods to register - * services without specifying a provider. - * - * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the - * {@link auto.$injector $injector} - * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by - * providers and services. - * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by - * services, not providers. - * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, - * that will be wrapped in a **service provider** object, whose `$get` property will contain the - * given factory function. - * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class` - * that will be wrapped in a **service provider** object, whose `$get` property will instantiate - * a new object using the given constructor function. - * - * See the individual methods for more information and examples. - */ - -/** - * @ngdoc method - * @name $provide#provider - * @description - * - * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions - * are constructor functions, whose instances are responsible for "providing" a factory for a - * service. - * - * Service provider names start with the name of the service they provide followed by `Provider`. - * For example, the {@link ng.$log $log} service has a provider called - * {@link ng.$logProvider $logProvider}. - * - * Service provider objects can have additional methods which allow configuration of the provider - * and its service. Importantly, you can configure what kind of service is created by the `$get` - * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a - * method {@link ng.$logProvider#debugEnabled debugEnabled} - * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the - * console or not. - * - * @param {string} name The name of the instance. NOTE: the provider will be available under `name + - 'Provider'` key. - * @param {(Object|function())} provider If the provider is: - * - * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using - * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. - * - `Constructor`: a new instance of the provider will be created using - * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. - * - * @returns {Object} registered provider instance - - * @example - * - * The following example shows how to create a simple event tracking service and register it using - * {@link auto.$provide#provider $provide.provider()}. - * - * ```js - * // Define the eventTracker provider - * function EventTrackerProvider() { - * var trackingUrl = '/track'; - * - * // A provider method for configuring where the tracked events should been saved - * this.setTrackingUrl = function(url) { - * trackingUrl = url; - * }; - * - * // The service factory function - * this.$get = ['$http', function($http) { - * var trackedEvents = {}; - * return { - * // Call this to track an event - * event: function(event) { - * var count = trackedEvents[event] || 0; - * count += 1; - * trackedEvents[event] = count; - * return count; - * }, - * // Call this to save the tracked events to the trackingUrl - * save: function() { - * $http.post(trackingUrl, trackedEvents); - * } - * }; - * }]; - * } - * - * describe('eventTracker', function() { - * var postSpy; - * - * beforeEach(module(function($provide) { - * // Register the eventTracker provider - * $provide.provider('eventTracker', EventTrackerProvider); - * })); - * - * beforeEach(module(function(eventTrackerProvider) { - * // Configure eventTracker provider - * eventTrackerProvider.setTrackingUrl('/custom-track'); - * })); - * - * it('tracks events', inject(function(eventTracker) { - * expect(eventTracker.event('login')).toEqual(1); - * expect(eventTracker.event('login')).toEqual(2); - * })); - * - * it('saves to the tracking url', inject(function(eventTracker, $http) { - * postSpy = spyOn($http, 'post'); - * eventTracker.event('login'); - * eventTracker.save(); - * expect(postSpy).toHaveBeenCalled(); - * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track'); - * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track'); - * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); - * })); - * }); - * ``` - */ - -/** - * @ngdoc method - * @name $provide#factory - * @description - * - * Register a **service factory**, which will be called to return the service instance. - * This is short for registering a service where its provider consists of only a `$get` property, - * which is the given service factory function. - * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to - * configure your service in a provider. - * - * @param {string} name The name of the instance. - * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand - * for `$provide.provider(name, {$get: $getFn})`. - * @returns {Object} registered provider instance - * - * @example - * Here is an example of registering a service - * ```js - * $provide.factory('ping', ['$http', function($http) { - * return function ping() { - * return $http.send('/ping'); - * }; - * }]); - * ``` - * You would then inject and use this service like this: - * ```js - * someModule.controller('Ctrl', ['ping', function(ping) { - * ping(); - * }]); - * ``` - */ - - -/** - * @ngdoc method - * @name $provide#service - * @description - * - * Register a **service constructor**, which will be invoked with `new` to create the service - * instance. - * This is short for registering a service where its provider's `$get` property is the service - * constructor function that will be used to instantiate the service instance. - * - * You should use {@link auto.$provide#service $provide.service(class)} if you define your service - * as a type/class. - * - * @param {string} name The name of the instance. - * @param {Function} constructor A class (constructor function) that will be instantiated. - * @returns {Object} registered provider instance - * - * @example - * Here is an example of registering a service using - * {@link auto.$provide#service $provide.service(class)}. - * ```js - * var Ping = function($http) { - * this.$http = $http; - * }; - * - * Ping.$inject = ['$http']; - * - * Ping.prototype.send = function() { - * return this.$http.get('/ping'); - * }; - * $provide.service('ping', Ping); - * ``` - * You would then inject and use this service like this: - * ```js - * someModule.controller('Ctrl', ['ping', function(ping) { - * ping.send(); - * }]); - * ``` - */ - - -/** - * @ngdoc method - * @name $provide#value - * @description - * - * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a - * number, an array, an object or a function. This is short for registering a service where its - * provider's `$get` property is a factory function that takes no arguments and returns the **value - * service**. - * - * Value services are similar to constant services, except that they cannot be injected into a - * module configuration function (see {@link angular.Module#config}) but they can be overridden by - * an Angular - * {@link auto.$provide#decorator decorator}. - * - * @param {string} name The name of the instance. - * @param {*} value The value. - * @returns {Object} registered provider instance - * - * @example - * Here are some examples of creating value services. - * ```js - * $provide.value('ADMIN_USER', 'admin'); - * - * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); - * - * $provide.value('halfOf', function(value) { - * return value / 2; - * }); - * ``` - */ - - -/** - * @ngdoc method - * @name $provide#constant - * @description - * - * Register a **constant service**, such as a string, a number, an array, an object or a function, - * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be - * injected into a module configuration function (see {@link angular.Module#config}) and it cannot - * be overridden by an Angular {@link auto.$provide#decorator decorator}. - * - * @param {string} name The name of the constant. - * @param {*} value The constant value. - * @returns {Object} registered instance - * - * @example - * Here a some examples of creating constants: - * ```js - * $provide.constant('SHARD_HEIGHT', 306); - * - * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); - * - * $provide.constant('double', function(value) { - * return value * 2; - * }); - * ``` - */ - - -/** - * @ngdoc method - * @name $provide#decorator - * @description - * - * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator - * intercepts the creation of a service, allowing it to override or modify the behaviour of the - * service. The object returned by the decorator may be the original service, or a new service - * object which replaces or wraps and delegates to the original service. - * - * @param {string} name The name of the service to decorate. - * @param {function()} decorator This function will be invoked when the service needs to be - * instantiated and should return the decorated service instance. The function is called using - * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. - * Local injection arguments: - * - * * `$delegate` - The original service instance, which can be monkey patched, configured, - * decorated or delegated to. - * - * @example - * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting - * calls to {@link ng.$log#error $log.warn()}. - * ```js - * $provide.decorator('$log', ['$delegate', function($delegate) { - * $delegate.warn = $delegate.error; - * return $delegate; - * }]); - * ``` - */ - - -function createInjector(modulesToLoad) { - var INSTANTIATING = {}, - providerSuffix = 'Provider', - path = [], - loadedModules = new HashMap([], true), - providerCache = { - $provide: { - provider: supportObject(provider), - factory: supportObject(factory), - service: supportObject(service), - value: supportObject(value), - constant: supportObject(constant), - decorator: decorator - } - }, - providerInjector = (providerCache.$injector = - createInternalInjector(providerCache, function() { - throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); - })), - instanceCache = {}, - instanceInjector = (instanceCache.$injector = - createInternalInjector(instanceCache, function(servicename) { - var provider = providerInjector.get(servicename + providerSuffix); - return instanceInjector.invoke(provider.$get, provider); - })); - - - forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); }); - - return instanceInjector; - - //////////////////////////////////// - // $provider - //////////////////////////////////// - - function supportObject(delegate) { - return function(key, value) { - if (isObject(key)) { - forEach(key, reverseParams(delegate)); - } else { - return delegate(key, value); - } - }; - } - - function provider(name, provider_) { - assertNotHasOwnProperty(name, 'service'); - if (isFunction(provider_) || isArray(provider_)) { - provider_ = providerInjector.instantiate(provider_); - } - if (!provider_.$get) { - throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); - } - return providerCache[name + providerSuffix] = provider_; - } - - function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); } - - function service(name, constructor) { - return factory(name, ['$injector', function($injector) { - return $injector.instantiate(constructor); - }]); - } - - function value(name, val) { return factory(name, valueFn(val)); } - - function constant(name, value) { - assertNotHasOwnProperty(name, 'constant'); - providerCache[name] = value; - instanceCache[name] = value; - } - - function decorator(serviceName, decorFn) { - var origProvider = providerInjector.get(serviceName + providerSuffix), - orig$get = origProvider.$get; - - origProvider.$get = function() { - var origInstance = instanceInjector.invoke(orig$get, origProvider); - return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); - }; - } - - //////////////////////////////////// - // Module Loading - //////////////////////////////////// - function loadModules(modulesToLoad){ - var runBlocks = [], moduleFn, invokeQueue, i, ii; - forEach(modulesToLoad, function(module) { - if (loadedModules.get(module)) return; - loadedModules.put(module, true); - - try { - if (isString(module)) { - moduleFn = angularModule(module); - runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); - - for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { - var invokeArgs = invokeQueue[i], - provider = providerInjector.get(invokeArgs[0]); - - provider[invokeArgs[1]].apply(provider, invokeArgs[2]); - } - } else if (isFunction(module)) { - runBlocks.push(providerInjector.invoke(module)); - } else if (isArray(module)) { - runBlocks.push(providerInjector.invoke(module)); - } else { - assertArgFn(module, 'module'); - } - } catch (e) { - if (isArray(module)) { - module = module[module.length - 1]; - } - if (e.message && e.stack && e.stack.indexOf(e.message) == -1) { - // Safari & FF's stack traces don't contain error.message content - // unlike those of Chrome and IE - // So if stack doesn't contain message, we create a new string that contains both. - // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. - /* jshint -W022 */ - e = e.message + '\n' + e.stack; - } - throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", - module, e.stack || e.message || e); - } - }); - return runBlocks; - } - - //////////////////////////////////// - // internal Injector - //////////////////////////////////// - - function createInternalInjector(cache, factory) { - - function getService(serviceName) { - if (cache.hasOwnProperty(serviceName)) { - if (cache[serviceName] === INSTANTIATING) { - throw $injectorMinErr('cdep', 'Circular dependency found: {0}', - serviceName + ' <- ' + path.join(' <- ')); - } - return cache[serviceName]; - } else { - try { - path.unshift(serviceName); - cache[serviceName] = INSTANTIATING; - return cache[serviceName] = factory(serviceName); - } catch (err) { - if (cache[serviceName] === INSTANTIATING) { - delete cache[serviceName]; - } - throw err; - } finally { - path.shift(); - } - } - } - - function invoke(fn, self, locals){ - var args = [], - $inject = annotate(fn), - length, i, - key; - - for(i = 0, length = $inject.length; i < length; i++) { - key = $inject[i]; - if (typeof key !== 'string') { - throw $injectorMinErr('itkn', - 'Incorrect injection token! Expected service name as string, got {0}', key); - } - args.push( - locals && locals.hasOwnProperty(key) - ? locals[key] - : getService(key) - ); - } - if (isArray(fn)) { - fn = fn[length]; - } - - // http://jsperf.com/angularjs-invoke-apply-vs-switch - // #5388 - return fn.apply(self, args); - } - - function instantiate(Type, locals) { - var Constructor = function() {}, - instance, returnedValue; - - // Check if Type is annotated and use just the given function at n-1 as parameter - // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); - Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; - instance = new Constructor(); - returnedValue = invoke(Type, instance, locals); - - return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; - } - - return { - invoke: invoke, - instantiate: instantiate, - get: getService, - annotate: annotate, - has: function(name) { - return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); - } - }; - } -} - -/** - * @ngdoc service - * @name $anchorScroll - * @kind function - * @requires $window - * @requires $location - * @requires $rootScope - * - * @description - * When called, it checks current value of `$location.hash()` and scrolls to the related element, - * according to rules specified in - * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). - * - * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor. - * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`. - * - * @example - - -
- Go to bottom - You're at the bottom! -
- - - function ScrollCtrl($scope, $location, $anchorScroll) { - $scope.gotoBottom = function (){ - // set the location.hash to the id of - // the element you wish to scroll to. - $location.hash('bottom'); - - // call $anchorScroll() - $anchorScroll(); - }; - } - - - #scrollArea { - height: 350px; - overflow: auto; - } - - #bottom { - display: block; - margin-top: 2000px; - } - - - */ -function $AnchorScrollProvider() { - - var autoScrollingEnabled = true; - - /** - * @ngdoc method - * @name $anchorScrollProvider#disableAutoScrolling - * - * @description - * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to - * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
- * Use this method to disable automatic scrolling. - * - * If automatic scrolling is disabled, one must explicitly call - * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the - * current hash. - */ - this.disableAutoScrolling = function() { - autoScrollingEnabled = false; - }; - - this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { - var document = $window.document; - - // helper function to get first anchor from a NodeList - // can't use filter.filter, as it accepts only instances of Array - // and IE can't convert NodeList to an array using [].slice - // TODO(vojta): use filter if we change it to accept lists as well - function getFirstAnchor(list) { - var result = null; - forEach(list, function(element) { - if (!result && lowercase(element.nodeName) === 'a') result = element; - }); - return result; - } - - function scroll() { - var hash = $location.hash(), elm; - - // empty hash, scroll to the top of the page - if (!hash) $window.scrollTo(0, 0); - - // element with given id - else if ((elm = document.getElementById(hash))) elm.scrollIntoView(); - - // first anchor with given name :-D - else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView(); - - // no element and hash == 'top', scroll to the top of the page - else if (hash === 'top') $window.scrollTo(0, 0); - } - - // does not scroll when user clicks on anchor link that is currently on - // (no url change, no $location.hash() change), browser native does scroll - if (autoScrollingEnabled) { - $rootScope.$watch(function autoScrollWatch() {return $location.hash();}, - function autoScrollWatchAction() { - $rootScope.$evalAsync(scroll); - }); - } - - return scroll; - }]; -} - -var $animateMinErr = minErr('$animate'); - -/** - * @ngdoc provider - * @name $animateProvider - * - * @description - * Default implementation of $animate that doesn't perform any animations, instead just - * synchronously performs DOM - * updates and calls done() callbacks. - * - * In order to enable animations the ngAnimate module has to be loaded. - * - * To see the functional implementation check out src/ngAnimate/animate.js - */ -var $AnimateProvider = ['$provide', function($provide) { - - - this.$$selectors = {}; - - - /** - * @ngdoc method - * @name $animateProvider#register - * - * @description - * Registers a new injectable animation factory function. The factory function produces the - * animation object which contains callback functions for each event that is expected to be - * animated. - * - * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` - * must be called once the element animation is complete. If a function is returned then the - * animation service will use this function to cancel the animation whenever a cancel event is - * triggered. - * - * - * ```js - * return { - * eventFn : function(element, done) { - * //code to run the animation - * //once complete, then run done() - * return function cancellationFunction() { - * //code to cancel the animation - * } - * } - * } - * ``` - * - * @param {string} name The name of the animation. - * @param {Function} factory The factory function that will be executed to return the animation - * object. - */ - this.register = function(name, factory) { - var key = name + '-animation'; - if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel', - "Expecting class selector starting with '.' got '{0}'.", name); - this.$$selectors[name.substr(1)] = key; - $provide.factory(key, factory); - }; - - /** - * @ngdoc method - * @name $animateProvider#classNameFilter - * - * @description - * Sets and/or returns the CSS class regular expression that is checked when performing - * an animation. Upon bootstrap the classNameFilter value is not set at all and will - * therefore enable $animate to attempt to perform an animation on any element. - * When setting the classNameFilter value, animations will only be performed on elements - * that successfully match the filter expression. This in turn can boost performance - * for low-powered devices as well as applications containing a lot of structural operations. - * @param {RegExp=} expression The className expression which will be checked against all animations - * @return {RegExp} The current CSS className expression value. If null then there is no expression value - */ - this.classNameFilter = function(expression) { - if(arguments.length === 1) { - this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; - } - return this.$$classNameFilter; - }; - - this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) { - - function async(fn) { - fn && $$asyncCallback(fn); - } - - /** - * - * @ngdoc service - * @name $animate - * @description The $animate service provides rudimentary DOM manipulation functions to - * insert, remove and move elements within the DOM, as well as adding and removing classes. - * This service is the core service used by the ngAnimate $animator service which provides - * high-level animation hooks for CSS and JavaScript. - * - * $animate is available in the AngularJS core, however, the ngAnimate module must be included - * to enable full out animation support. Otherwise, $animate will only perform simple DOM - * manipulation operations. - * - * To learn more about enabling animation support, click here to visit the {@link ngAnimate - * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service - * page}. - */ - return { - - /** - * - * @ngdoc method - * @name $animate#enter - * @kind function - * @description Inserts the element into the DOM either after the `after` element or within - * the `parent` element. Once complete, the done() callback will be fired (if provided). - * @param {DOMElement} element the element which will be inserted into the DOM - * @param {DOMElement} parent the parent element which will append the element as - * a child (if the after element is not present) - * @param {DOMElement} after the sibling element which will append the element - * after itself - * @param {Function=} done callback function that will be called after the element has been - * inserted into the DOM - */ - enter : function(element, parent, after, done) { - if (after) { - after.after(element); - } else { - if (!parent || !parent[0]) { - parent = after.parent(); - } - parent.append(element); - } - async(done); - }, - - /** - * - * @ngdoc method - * @name $animate#leave - * @kind function - * @description Removes the element from the DOM. Once complete, the done() callback will be - * fired (if provided). - * @param {DOMElement} element the element which will be removed from the DOM - * @param {Function=} done callback function that will be called after the element has been - * removed from the DOM - */ - leave : function(element, done) { - element.remove(); - async(done); - }, - - /** - * - * @ngdoc method - * @name $animate#move - * @kind function - * @description Moves the position of the provided element within the DOM to be placed - * either after the `after` element or inside of the `parent` element. Once complete, the - * done() callback will be fired (if provided). - * - * @param {DOMElement} element the element which will be moved around within the - * DOM - * @param {DOMElement} parent the parent element where the element will be - * inserted into (if the after element is not present) - * @param {DOMElement} after the sibling element where the element will be - * positioned next to - * @param {Function=} done the callback function (if provided) that will be fired after the - * element has been moved to its new position - */ - move : function(element, parent, after, done) { - // Do not remove element before insert. Removing will cause data associated with the - // element to be dropped. Insert will implicitly do the remove. - this.enter(element, parent, after, done); - }, - - /** - * - * @ngdoc method - * @name $animate#addClass - * @kind function - * @description Adds the provided className CSS class value to the provided element. Once - * complete, the done() callback will be fired (if provided). - * @param {DOMElement} element the element which will have the className value - * added to it - * @param {string} className the CSS class which will be added to the element - * @param {Function=} done the callback function (if provided) that will be fired after the - * className value has been added to the element - */ - addClass : function(element, className, done) { - className = isString(className) ? - className : - isArray(className) ? className.join(' ') : ''; - forEach(element, function (element) { - jqLiteAddClass(element, className); - }); - async(done); - }, - - /** - * - * @ngdoc method - * @name $animate#removeClass - * @kind function - * @description Removes the provided className CSS class value from the provided element. - * Once complete, the done() callback will be fired (if provided). - * @param {DOMElement} element the element which will have the className value - * removed from it - * @param {string} className the CSS class which will be removed from the element - * @param {Function=} done the callback function (if provided) that will be fired after the - * className value has been removed from the element - */ - removeClass : function(element, className, done) { - className = isString(className) ? - className : - isArray(className) ? className.join(' ') : ''; - forEach(element, function (element) { - jqLiteRemoveClass(element, className); - }); - async(done); - }, - - /** - * - * @ngdoc method - * @name $animate#setClass - * @kind function - * @description Adds and/or removes the given CSS classes to and from the element. - * Once complete, the done() callback will be fired (if provided). - * @param {DOMElement} element the element which will have its CSS classes changed - * removed from it - * @param {string} add the CSS classes which will be added to the element - * @param {string} remove the CSS class which will be removed from the element - * @param {Function=} done the callback function (if provided) that will be fired after the - * CSS classes have been set on the element - */ - setClass : function(element, add, remove, done) { - forEach(element, function (element) { - jqLiteAddClass(element, add); - jqLiteRemoveClass(element, remove); - }); - async(done); - }, - - enabled : noop - }; - }]; -}]; - -function $$AsyncCallbackProvider(){ - this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) { - return $$rAF.supported - ? function(fn) { return $$rAF(fn); } - : function(fn) { - return $timeout(fn, 0, false); - }; - }]; -} - -/* global stripHash: true */ - -/** - * ! This is a private undocumented service ! - * - * @name $browser - * @requires $log - * @description - * This object has two goals: - * - * - hide all the global state in the browser caused by the window object - * - abstract away all the browser specific features and inconsistencies - * - * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser` - * service, which can be used for convenient testing of the application without the interaction with - * the real browser apis. - */ -/** - * @param {object} window The global window object. - * @param {object} document jQuery wrapped document. - * @param {function()} XHR XMLHttpRequest constructor. - * @param {object} $log console.log or an object with the same interface. - * @param {object} $sniffer $sniffer service - */ -function Browser(window, document, $log, $sniffer) { - var self = this, - rawDocument = document[0], - location = window.location, - history = window.history, - setTimeout = window.setTimeout, - clearTimeout = window.clearTimeout, - pendingDeferIds = {}; - - self.isMock = false; - - var outstandingRequestCount = 0; - var outstandingRequestCallbacks = []; - - // TODO(vojta): remove this temporary api - self.$$completeOutstandingRequest = completeOutstandingRequest; - self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; }; - - /** - * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks` - * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed. - */ - function completeOutstandingRequest(fn) { - try { - fn.apply(null, sliceArgs(arguments, 1)); - } finally { - outstandingRequestCount--; - if (outstandingRequestCount === 0) { - while(outstandingRequestCallbacks.length) { - try { - outstandingRequestCallbacks.pop()(); - } catch (e) { - $log.error(e); - } - } - } - } - } - - /** - * @private - * Note: this method is used only by scenario runner - * TODO(vojta): prefix this method with $$ ? - * @param {function()} callback Function that will be called when no outstanding request - */ - self.notifyWhenNoOutstandingRequests = function(callback) { - // force browser to execute all pollFns - this is needed so that cookies and other pollers fire - // at some deterministic time in respect to the test runner's actions. Leaving things up to the - // regular poller would result in flaky tests. - forEach(pollFns, function(pollFn){ pollFn(); }); - - if (outstandingRequestCount === 0) { - callback(); - } else { - outstandingRequestCallbacks.push(callback); - } - }; - - ////////////////////////////////////////////////////////////// - // Poll Watcher API - ////////////////////////////////////////////////////////////// - var pollFns = [], - pollTimeout; - - /** - * @name $browser#addPollFn - * - * @param {function()} fn Poll function to add - * - * @description - * Adds a function to the list of functions that poller periodically executes, - * and starts polling if not started yet. - * - * @returns {function()} the added function - */ - self.addPollFn = function(fn) { - if (isUndefined(pollTimeout)) startPoller(100, setTimeout); - pollFns.push(fn); - return fn; - }; - - /** - * @param {number} interval How often should browser call poll functions (ms) - * @param {function()} setTimeout Reference to a real or fake `setTimeout` function. - * - * @description - * Configures the poller to run in the specified intervals, using the specified - * setTimeout fn and kicks it off. - */ - function startPoller(interval, setTimeout) { - (function check() { - forEach(pollFns, function(pollFn){ pollFn(); }); - pollTimeout = setTimeout(check, interval); - })(); - } - - ////////////////////////////////////////////////////////////// - // URL API - ////////////////////////////////////////////////////////////// - - var lastBrowserUrl = location.href, - baseElement = document.find('base'), - reloadLocation = null; - - /** - * @name $browser#url - * - * @description - * GETTER: - * Without any argument, this method just returns current value of location.href. - * - * SETTER: - * With at least one argument, this method sets url to new value. - * If html5 history api supported, pushState/replaceState is used, otherwise - * location.href/location.replace is used. - * Returns its own instance to allow chaining - * - * NOTE: this api is intended for use only by the $location service. Please use the - * {@link ng.$location $location service} to change url. - * - * @param {string} url New url (when used as setter) - * @param {boolean=} replace Should new url replace current history record ? - */ - self.url = function(url, replace) { - // Android Browser BFCache causes location, history reference to become stale. - if (location !== window.location) location = window.location; - if (history !== window.history) history = window.history; - - // setter - if (url) { - if (lastBrowserUrl == url) return; - var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); - lastBrowserUrl = url; - // Don't use history API if only the hash changed - // due to a bug in IE10/IE11 which leads - // to not firing a `hashchange` nor `popstate` event - // in some cases (see #9143). - if (!sameBase && $sniffer.history) { - if (replace) history.replaceState(null, '', url); - else { - history.pushState(null, '', url); - // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462 - baseElement.attr('href', baseElement.attr('href')); - } - } else { - if (!sameBase) { - reloadLocation = url; - } - if (replace) { - location.replace(url); - } else { - location.href = url; - } - } - return self; - // getter - } else { - // - reloadLocation is needed as browsers don't allow to read out - // the new location.href if a reload happened. - // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 - return reloadLocation || location.href.replace(/%27/g,"'"); - } - }; - - var urlChangeListeners = [], - urlChangeInit = false; - - function fireUrlChange() { - if (lastBrowserUrl == self.url()) return; - - lastBrowserUrl = self.url(); - forEach(urlChangeListeners, function(listener) { - listener(self.url()); - }); - } - - /** - * @name $browser#onUrlChange - * - * @description - * Register callback function that will be called, when url changes. - * - * It's only called when the url is changed from outside of angular: - * - user types different url into address bar - * - user clicks on history (forward/back) button - * - user clicks on a link - * - * It's not called when url is changed by $browser.url() method - * - * The listener gets called with new url as parameter. - * - * NOTE: this api is intended for use only by the $location service. Please use the - * {@link ng.$location $location service} to monitor url changes in angular apps. - * - * @param {function(string)} listener Listener function to be called when url changes. - * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. - */ - self.onUrlChange = function(callback) { - // TODO(vojta): refactor to use node's syntax for events - if (!urlChangeInit) { - // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) - // don't fire popstate when user change the address bar and don't fire hashchange when url - // changed by push/replaceState - - // html5 history api - popstate event - if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange); - // hashchange event - if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange); - // polling - else self.addPollFn(fireUrlChange); - - urlChangeInit = true; - } - - urlChangeListeners.push(callback); - return callback; - }; - - /** - * Checks whether the url has changed outside of Angular. - * Needs to be exported to be able to check for changes that have been done in sync, - * as hashchange/popstate events fire in async. - */ - self.$$checkUrlChange = fireUrlChange; - - ////////////////////////////////////////////////////////////// - // Misc API - ////////////////////////////////////////////////////////////// - - /** - * @name $browser#baseHref - * - * @description - * Returns current - * (always relative - without domain) - * - * @returns {string} The current base href - */ - self.baseHref = function() { - var href = baseElement.attr('href'); - return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : ''; - }; - - ////////////////////////////////////////////////////////////// - // Cookies API - ////////////////////////////////////////////////////////////// - var lastCookies = {}; - var lastCookieString = ''; - var cookiePath = self.baseHref(); - - /** - * @name $browser#cookies - * - * @param {string=} name Cookie name - * @param {string=} value Cookie value - * - * @description - * The cookies method provides a 'private' low level access to browser cookies. - * It is not meant to be used directly, use the $cookie service instead. - * - * The return values vary depending on the arguments that the method was called with as follows: - * - * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify - * it - * - cookies(name, value) -> set name to value, if value is undefined delete the cookie - * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that - * way) - * - * @returns {Object} Hash of all cookies (if called without any parameter) - */ - self.cookies = function(name, value) { - /* global escape: false, unescape: false */ - var cookieLength, cookieArray, cookie, i, index; - - if (name) { - if (value === undefined) { - rawDocument.cookie = escape(name) + "=;path=" + cookiePath + - ";expires=Thu, 01 Jan 1970 00:00:00 GMT"; - } else { - if (isString(value)) { - cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + - ';path=' + cookiePath).length + 1; - - // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: - // - 300 cookies - // - 20 cookies per unique domain - // - 4096 bytes per cookie - if (cookieLength > 4096) { - $log.warn("Cookie '"+ name + - "' possibly not set or overflowed because it was too large ("+ - cookieLength + " > 4096 bytes)!"); - } - } - } - } else { - if (rawDocument.cookie !== lastCookieString) { - lastCookieString = rawDocument.cookie; - cookieArray = lastCookieString.split("; "); - lastCookies = {}; - - for (i = 0; i < cookieArray.length; i++) { - cookie = cookieArray[i]; - index = cookie.indexOf('='); - if (index > 0) { //ignore nameless cookies - name = unescape(cookie.substring(0, index)); - // the first value that is seen for a cookie is the most - // specific one. values for the same cookie name that - // follow are for less specific paths. - if (lastCookies[name] === undefined) { - lastCookies[name] = unescape(cookie.substring(index + 1)); - } - } - } - } - return lastCookies; - } - }; - - - /** - * @name $browser#defer - * @param {function()} fn A function, who's execution should be deferred. - * @param {number=} [delay=0] of milliseconds to defer the function execution. - * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. - * - * @description - * Executes a fn asynchronously via `setTimeout(fn, delay)`. - * - * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using - * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed - * via `$browser.defer.flush()`. - * - */ - self.defer = function(fn, delay) { - var timeoutId; - outstandingRequestCount++; - timeoutId = setTimeout(function() { - delete pendingDeferIds[timeoutId]; - completeOutstandingRequest(fn); - }, delay || 0); - pendingDeferIds[timeoutId] = true; - return timeoutId; - }; - - - /** - * @name $browser#defer.cancel - * - * @description - * Cancels a deferred task identified with `deferId`. - * - * @param {*} deferId Token returned by the `$browser.defer` function. - * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully - * canceled. - */ - self.defer.cancel = function(deferId) { - if (pendingDeferIds[deferId]) { - delete pendingDeferIds[deferId]; - clearTimeout(deferId); - completeOutstandingRequest(noop); - return true; - } - return false; - }; - -} - -function $BrowserProvider(){ - this.$get = ['$window', '$log', '$sniffer', '$document', - function( $window, $log, $sniffer, $document){ - return new Browser($window, $document, $log, $sniffer); - }]; -} - -/** - * @ngdoc service - * @name $cacheFactory - * - * @description - * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to - * them. - * - * ```js - * - * var cache = $cacheFactory('cacheId'); - * expect($cacheFactory.get('cacheId')).toBe(cache); - * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined(); - * - * cache.put("key", "value"); - * cache.put("another key", "another value"); - * - * // We've specified no options on creation - * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); - * - * ``` - * - * - * @param {string} cacheId Name or id of the newly created cache. - * @param {object=} options Options object that specifies the cache behavior. Properties: - * - * - `{number=}` `capacity` — turns the cache into LRU cache. - * - * @returns {object} Newly created cache object with the following set of methods: - * - * - `{object}` `info()` — Returns id, size, and options of cache. - * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns - * it. - * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. - * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. - * - `{void}` `removeAll()` — Removes all cached values. - * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. - * - * @example - - -
- - - - -

Cached Values

-
- - : - -
- -

Cache Info

-
- - : - -
-
-
- - angular.module('cacheExampleApp', []). - controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) { - $scope.keys = []; - $scope.cache = $cacheFactory('cacheId'); - $scope.put = function(key, value) { - if ($scope.cache.get(key) === undefined) { - $scope.keys.push(key); - } - $scope.cache.put(key, value === undefined ? null : value); - }; - }]); - - - p { - margin: 10px 0 3px; - } - -
- */ -function $CacheFactoryProvider() { - - this.$get = function() { - var caches = {}; - - function cacheFactory(cacheId, options) { - if (cacheId in caches) { - throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId); - } - - var size = 0, - stats = extend({}, options, {id: cacheId}), - data = {}, - capacity = (options && options.capacity) || Number.MAX_VALUE, - lruHash = {}, - freshEnd = null, - staleEnd = null; - - /** - * @ngdoc type - * @name $cacheFactory.Cache - * - * @description - * A cache object used to store and retrieve data, primarily used by - * {@link $http $http} and the {@link ng.directive:script script} directive to cache - * templates and other data. - * - * ```js - * angular.module('superCache') - * .factory('superCache', ['$cacheFactory', function($cacheFactory) { - * return $cacheFactory('super-cache'); - * }]); - * ``` - * - * Example test: - * - * ```js - * it('should behave like a cache', inject(function(superCache) { - * superCache.put('key', 'value'); - * superCache.put('another key', 'another value'); - * - * expect(superCache.info()).toEqual({ - * id: 'super-cache', - * size: 2 - * }); - * - * superCache.remove('another key'); - * expect(superCache.get('another key')).toBeUndefined(); - * - * superCache.removeAll(); - * expect(superCache.info()).toEqual({ - * id: 'super-cache', - * size: 0 - * }); - * })); - * ``` - */ - return caches[cacheId] = { - - /** - * @ngdoc method - * @name $cacheFactory.Cache#put - * @kind function - * - * @description - * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be - * retrieved later, and incrementing the size of the cache if the key was not already - * present in the cache. If behaving like an LRU cache, it will also remove stale - * entries from the set. - * - * It will not insert undefined values into the cache. - * - * @param {string} key the key under which the cached data is stored. - * @param {*} value the value to store alongside the key. If it is undefined, the key - * will not be stored. - * @returns {*} the value stored. - */ - put: function(key, value) { - if (capacity < Number.MAX_VALUE) { - var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); - - refresh(lruEntry); - } - - if (isUndefined(value)) return; - if (!(key in data)) size++; - data[key] = value; - - if (size > capacity) { - this.remove(staleEnd.key); - } - - return value; - }, - - /** - * @ngdoc method - * @name $cacheFactory.Cache#get - * @kind function - * - * @description - * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object. - * - * @param {string} key the key of the data to be retrieved - * @returns {*} the value stored. - */ - get: function(key) { - if (capacity < Number.MAX_VALUE) { - var lruEntry = lruHash[key]; - - if (!lruEntry) return; - - refresh(lruEntry); - } - - return data[key]; - }, - - - /** - * @ngdoc method - * @name $cacheFactory.Cache#remove - * @kind function - * - * @description - * Removes an entry from the {@link $cacheFactory.Cache Cache} object. - * - * @param {string} key the key of the entry to be removed - */ - remove: function(key) { - if (capacity < Number.MAX_VALUE) { - var lruEntry = lruHash[key]; - - if (!lruEntry) return; - - if (lruEntry == freshEnd) freshEnd = lruEntry.p; - if (lruEntry == staleEnd) staleEnd = lruEntry.n; - link(lruEntry.n,lruEntry.p); - - delete lruHash[key]; - } - - delete data[key]; - size--; - }, - - - /** - * @ngdoc method - * @name $cacheFactory.Cache#removeAll - * @kind function - * - * @description - * Clears the cache object of any entries. - */ - removeAll: function() { - data = {}; - size = 0; - lruHash = {}; - freshEnd = staleEnd = null; - }, - - - /** - * @ngdoc method - * @name $cacheFactory.Cache#destroy - * @kind function - * - * @description - * Destroys the {@link $cacheFactory.Cache Cache} object entirely, - * removing it from the {@link $cacheFactory $cacheFactory} set. - */ - destroy: function() { - data = null; - stats = null; - lruHash = null; - delete caches[cacheId]; - }, - - - /** - * @ngdoc method - * @name $cacheFactory.Cache#info - * @kind function - * - * @description - * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}. - * - * @returns {object} an object with the following properties: - *
    - *
  • **id**: the id of the cache instance
  • - *
  • **size**: the number of entries kept in the cache instance
  • - *
  • **...**: any additional properties from the options object when creating the - * cache.
  • - *
- */ - info: function() { - return extend({}, stats, {size: size}); - } - }; - - - /** - * makes the `entry` the freshEnd of the LRU linked list - */ - function refresh(entry) { - if (entry != freshEnd) { - if (!staleEnd) { - staleEnd = entry; - } else if (staleEnd == entry) { - staleEnd = entry.n; - } - - link(entry.n, entry.p); - link(entry, freshEnd); - freshEnd = entry; - freshEnd.n = null; - } - } - - - /** - * bidirectionally links two entries of the LRU linked list - */ - function link(nextEntry, prevEntry) { - if (nextEntry != prevEntry) { - if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify - if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify - } - } - } - - - /** - * @ngdoc method - * @name $cacheFactory#info - * - * @description - * Get information about all the caches that have been created - * - * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info` - */ - cacheFactory.info = function() { - var info = {}; - forEach(caches, function(cache, cacheId) { - info[cacheId] = cache.info(); - }); - return info; - }; - - - /** - * @ngdoc method - * @name $cacheFactory#get - * - * @description - * Get access to a cache object by the `cacheId` used when it was created. - * - * @param {string} cacheId Name or id of a cache to access. - * @returns {object} Cache object identified by the cacheId or undefined if no such cache. - */ - cacheFactory.get = function(cacheId) { - return caches[cacheId]; - }; - - - return cacheFactory; - }; -} - -/** - * @ngdoc service - * @name $templateCache - * - * @description - * The first time a template is used, it is loaded in the template cache for quick retrieval. You - * can load templates directly into the cache in a `script` tag, or by consuming the - * `$templateCache` service directly. - * - * Adding via the `script` tag: - * - * ```html - * - * ``` - * - * **Note:** the `script` tag containing the template does not need to be included in the `head` of - * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, - * element with ng-app attribute), otherwise the template will be ignored. - * - * Adding via the $templateCache service: - * - * ```js - * var myApp = angular.module('myApp', []); - * myApp.run(function($templateCache) { - * $templateCache.put('templateId.html', 'This is the content of the template'); - * }); - * ``` - * - * To retrieve the template later, simply use it in your HTML: - * ```html - *
- * ``` - * - * or get it via Javascript: - * ```js - * $templateCache.get('templateId.html') - * ``` - * - * See {@link ng.$cacheFactory $cacheFactory}. - * - */ -function $TemplateCacheProvider() { - this.$get = ['$cacheFactory', function($cacheFactory) { - return $cacheFactory('templates'); - }]; -} - -/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! - * - * DOM-related variables: - * - * - "node" - DOM Node - * - "element" - DOM Element or Node - * - "$node" or "$element" - jqLite-wrapped node or element - * - * - * Compiler related stuff: - * - * - "linkFn" - linking fn of a single directive - * - "nodeLinkFn" - function that aggregates all linking fns for a particular node - * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node - * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList) - */ - - -/** - * @ngdoc service - * @name $compile - * @kind function - * - * @description - * Compiles an HTML string or DOM into a template and produces a template function, which - * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. - * - * The compilation is a process of walking the DOM tree and matching DOM elements to - * {@link ng.$compileProvider#directive directives}. - * - *
- * **Note:** This document is an in-depth reference of all directive options. - * For a gentle introduction to directives with examples of common use cases, - * see the {@link guide/directive directive guide}. - *
- * - * ## Comprehensive Directive API - * - * There are many different options for a directive. - * - * The difference resides in the return value of the factory function. - * You can either return a "Directive Definition Object" (see below) that defines the directive properties, - * or just the `postLink` function (all other properties will have the default values). - * - *
- * **Best Practice:** It's recommended to use the "directive definition object" form. - *
- * - * Here's an example directive declared with a Directive Definition Object: - * - * ```js - * var myModule = angular.module(...); - * - * myModule.directive('directiveName', function factory(injectables) { - * var directiveDefinitionObject = { - * priority: 0, - * template: '
', // or // function(tElement, tAttrs) { ... }, - * // or - * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, - * transclude: false, - * restrict: 'A', - * scope: false, - * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, - * controllerAs: 'stringAlias', - * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], - * compile: function compile(tElement, tAttrs, transclude) { - * return { - * pre: function preLink(scope, iElement, iAttrs, controller) { ... }, - * post: function postLink(scope, iElement, iAttrs, controller) { ... } - * } - * // or - * // return function postLink( ... ) { ... } - * }, - * // or - * // link: { - * // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, - * // post: function postLink(scope, iElement, iAttrs, controller) { ... } - * // } - * // or - * // link: function postLink( ... ) { ... } - * }; - * return directiveDefinitionObject; - * }); - * ``` - * - *
- * **Note:** Any unspecified options will use the default value. You can see the default values below. - *
- * - * Therefore the above can be simplified as: - * - * ```js - * var myModule = angular.module(...); - * - * myModule.directive('directiveName', function factory(injectables) { - * var directiveDefinitionObject = { - * link: function postLink(scope, iElement, iAttrs) { ... } - * }; - * return directiveDefinitionObject; - * // or - * // return function postLink(scope, iElement, iAttrs) { ... } - * }); - * ``` - * - * - * - * ### Directive Definition Object - * - * The directive definition object provides instructions to the {@link ng.$compile - * compiler}. The attributes are: - * - * #### `priority` - * When there are multiple directives defined on a single DOM element, sometimes it - * is necessary to specify the order in which the directives are applied. The `priority` is used - * to sort the directives before their `compile` functions get called. Priority is defined as a - * number. Directives with greater numerical `priority` are compiled first. Pre-link functions - * are also run in priority order, but post-link functions are run in reverse order. The order - * of directives with the same priority is undefined. The default priority is `0`. - * - * #### `terminal` - * If set to true then the current `priority` will be the last set of directives - * which will execute (any directives at the current priority will still execute - * as the order of execution on same `priority` is undefined). - * - * #### `scope` - * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the - * same element request a new scope, only one new scope is created. The new scope rule does not - * apply for the root of the template since the root of the template always gets a new scope. - * - * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from - * normal scope in that it does not prototypically inherit from the parent scope. This is useful - * when creating reusable components, which should not accidentally read or modify data in the - * parent scope. - * - * The 'isolate' scope takes an object hash which defines a set of local scope properties - * derived from the parent scope. These local properties are useful for aliasing values for - * templates. Locals definition is a hash of local scope property to its source: - * - * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is - * always a string since DOM attributes are strings. If no `attr` name is specified then the - * attribute name is assumed to be the same as the local name. - * Given `` and widget definition - * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect - * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the - * `localName` property on the widget scope. The `name` is read from the parent scope (not - * component scope). - * - * * `=` or `=attr` - set up bi-directional binding between a local scope property and the - * parent scope property of name defined via the value of the `attr` attribute. If no `attr` - * name is specified then the attribute name is assumed to be the same as the local name. - * Given `` and widget definition of - * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the - * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected - * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent - * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You - * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. - * - * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. - * If no `attr` name is specified then the attribute name is assumed to be the same as the - * local name. Given `` and widget definition of - * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to - * a function wrapper for the `count = count + value` expression. Often it's desirable to - * pass data from the isolated scope via an expression to the parent scope, this can be - * done by passing a map of local variable names and values into the expression wrapper fn. - * For example, if the expression is `increment(amount)` then we can specify the amount value - * by calling the `localFn` as `localFn({amount: 22})`. - * - * - * - * #### `controller` - * Controller constructor function. The controller is instantiated before the - * pre-linking phase and it is shared with other directives (see - * `require` attribute). This allows the directives to communicate with each other and augment - * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: - * - * * `$scope` - Current scope associated with the element - * * `$element` - Current element - * * `$attrs` - Current attributes object for the element - * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope. - * The scope can be overridden by an optional first argument. - * `function([scope], cloneLinkingFn)`. - * - * - * #### `require` - * Require another directive and inject its controller as the fourth argument to the linking function. The - * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the - * injected argument will be an array in corresponding order. If no such directive can be - * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with: - * - * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. - * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. - * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found. - * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass - * `null` to the `link` fn if not found. - * - * - * #### `controllerAs` - * Controller alias at the directive scope. An alias for the controller so it - * can be referenced at the directive template. The directive needs to define a scope for this - * configuration to be used. Useful in the case when directive is used as component. - * - * - * #### `restrict` - * String of subset of `EACM` which restricts the directive to a specific directive - * declaration style. If omitted, the default (attributes only) is used. - * - * * `E` - Element name: `` - * * `A` - Attribute (default): `
` - * * `C` - Class: `
` - * * `M` - Comment: `` - * - * - * #### `template` - * HTML markup that may: - * * Replace the contents of the directive's element (default). - * * Replace the directive's element itself (if `replace` is true - DEPRECATED). - * * Wrap the contents of the directive's element (if `transclude` is true). - * - * Value may be: - * - * * A string. For example `
{{delete_str}}
`. - * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile` - * function api below) and returns a string value. - * - * - * #### `templateUrl` - * Same as `template` but the template is loaded from the specified URL. Because - * the template loading is asynchronous the compilation/linking is suspended until the template - * is loaded. - * - * You can specify `templateUrl` as a string representing the URL or as a function which takes two - * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns - * a string value representing the url. In either case, the template URL is passed through {@link - * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}. - * - * - * #### `replace` ([*DEPRECATED*!], will be removed in next major release) - * specify what the template should replace. Defaults to `false`. - * - * * `true` - the template will replace the directive's element. - * * `false` - the template will replace the contents of the directive's element. - * - * The replacement process migrates all of the attributes / classes from the old element to the new - * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive - * Directives Guide} for an example. - * - * #### `transclude` - * compile the content of the element and make it available to the directive. - * Typically used with {@link ng.directive:ngTransclude - * ngTransclude}. The advantage of transclusion is that the linking function receives a - * transclusion function which is pre-bound to the correct scope. In a typical setup the widget - * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate` - * scope. This makes it possible for the widget to have private state, and the transclusion to - * be bound to the parent (pre-`isolate`) scope. - * - * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the - * directive's element or the entire element: - * - * * `true` - transclude the content (i.e. the child nodes) of the directive's element. - * * `'element'` - transclude the whole of the directive's element including any directives on this - * element that defined at a lower priority than this directive. When used, the `template` - * property is ignored. - * - *
- * **Note:** When testing an element transclude directive you must not place the directive at the root of the - * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives - * Testing Transclusion Directives}. - *
- * - * #### `compile` - * - * ```js - * function compile(tElement, tAttrs, transclude) { ... } - * ``` - * - * The compile function deals with transforming the template DOM. Since most directives do not do - * template transformation, it is not used often. The compile function takes the following arguments: - * - * * `tElement` - template element - The element where the directive has been declared. It is - * safe to do template transformation on the element and child elements only. - * - * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared - * between all directive compile functions. - * - * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` - * - *
- * **Note:** The template instance and the link instance may be different objects if the template has - * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that - * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration - * should be done in a linking function rather than in a compile function. - *
- - *
- * **Note:** The compile function cannot handle directives that recursively use themselves in their - * own templates or compile functions. Compiling these directives results in an infinite loop and a - * stack overflow errors. - * - * This can be avoided by manually using $compile in the postLink function to imperatively compile - * a directive's template instead of relying on automatic template compilation via `template` or - * `templateUrl` declaration or manual compilation inside the compile function. - *
- * - *
- * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it - * e.g. does not know about the right outer scope. Please use the transclude function that is passed - * to the link function instead. - *
- - * A compile function can have a return value which can be either a function or an object. - * - * * returning a (post-link) function - is equivalent to registering the linking function via the - * `link` property of the config object when the compile function is empty. - * - * * returning an object with function(s) registered via `pre` and `post` properties - allows you to - * control when a linking function should be called during the linking phase. See info about - * pre-linking and post-linking functions below. - * - * - * #### `link` - * This property is used only if the `compile` property is not defined. - * - * ```js - * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } - * ``` - * - * The link function is responsible for registering DOM listeners as well as updating the DOM. It is - * executed after the template has been cloned. This is where most of the directive logic will be - * put. - * - * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the - * directive for registering {@link ng.$rootScope.Scope#$watch watches}. - * - * * `iElement` - instance element - The element where the directive is to be used. It is safe to - * manipulate the children of the element only in `postLink` function since the children have - * already been linked. - * - * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared - * between all directive linking functions. - * - * * `controller` - a controller instance - A controller instance if at least one directive on the - * element defines a controller. The controller is shared among all the directives, which allows - * the directives to use the controllers as a communication channel. - * - * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. - * The scope can be overridden by an optional first argument. This is the same as the `$transclude` - * parameter of directive controllers. - * `function([scope], cloneLinkingFn)`. - * - * - * #### Pre-linking function - * - * Executed before the child elements are linked. Not safe to do DOM transformation since the - * compiler linking function will fail to locate the correct elements for linking. - * - * #### Post-linking function - * - * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function. - * - * - * ### Attributes - * - * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the - * `link()` or `compile()` functions. It has a variety of uses. - * - * accessing *Normalized attribute names:* - * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. - * the attributes object allows for normalized access to - * the attributes. - * - * * *Directive inter-communication:* All directives share the same instance of the attributes - * object which allows the directives to use the attributes object as inter directive - * communication. - * - * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object - * allowing other directives to read the interpolated value. - * - * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes - * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also - * the only way to easily get the actual value because during the linking phase the interpolation - * hasn't been evaluated yet and so the value is at this time set to `undefined`. - * - * ```js - * function linkingFn(scope, elm, attrs, ctrl) { - * // get the attribute value - * console.log(attrs.ngModel); - * - * // change the attribute - * attrs.$set('ngModel', 'new value'); - * - * // observe changes to interpolated attribute - * attrs.$observe('ngModel', function(value) { - * console.log('ngModel has changed value to ' + value); - * }); - * } - * ``` - * - * ## Example - * - *
- * **Note**: Typically directives are registered with `module.directive`. The example below is - * to illustrate how `$compile` works. - *
- * - - - -
-
-
-
-
-
- - it('should auto compile', function() { - var textarea = $('textarea'); - var output = $('div[compile]'); - // The initial state reads 'Hello Angular'. - expect(output.getText()).toBe('Hello Angular'); - textarea.clear(); - textarea.sendKeys('{{name}}!'); - expect(output.getText()).toBe('Angular!'); - }); - -
- - * - * - * @param {string|DOMElement} element Element or HTML string to compile into a template function. - * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives. - * @param {number} maxPriority only apply directives lower than given priority (Only effects the - * root element(s), not their children) - * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template - * (a DOM element/tree) to a scope. Where: - * - * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to. - * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the - * `template` and call the `cloneAttachFn` function allowing the caller to attach the - * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is - * called as:
`cloneAttachFn(clonedElement, scope)` where: - * - * * `clonedElement` - is a clone of the original `element` passed into the compiler. - * * `scope` - is the current scope with which the linking function is working with. - * - * Calling the linking function returns the element of the template. It is either the original - * element passed in, or the clone of the element if the `cloneAttachFn` is provided. - * - * After linking the view is not updated until after a call to $digest which typically is done by - * Angular automatically. - * - * If you need access to the bound view, there are two ways to do it: - * - * - If you are not asking the linking function to clone the template, create the DOM element(s) - * before you send them to the compiler and keep this reference around. - * ```js - * var element = $compile('

{{total}}

')(scope); - * ``` - * - * - if on the other hand, you need the element to be cloned, the view reference from the original - * example would not point to the clone, but rather to the original template that was cloned. In - * this case, you can access the clone via the cloneAttachFn: - * ```js - * var templateElement = angular.element('

{{total}}

'), - * scope = ....; - * - * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { - * //attach the clone to DOM document at the right place - * }); - * - * //now we have reference to the cloned DOM via `clonedElement` - * ``` - * - * - * For information on how the compiler works, see the - * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. - */ - -var $compileMinErr = minErr('$compile'); - -/** - * @ngdoc provider - * @name $compileProvider - * @kind function - * - * @description - */ -$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; -function $CompileProvider($provide, $$sanitizeUriProvider) { - var hasDirectives = {}, - Suffix = 'Directive', - COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/, - CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/; - - // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes - // The assumption is that future DOM event attribute names will begin with - // 'on' and be composed of only English letters. - var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; - - /** - * @ngdoc method - * @name $compileProvider#directive - * @kind function - * - * @description - * Register a new directive with the compiler. - * - * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which - * will match as ng-bind), or an object map of directives where the keys are the - * names and the values are the factories. - * @param {Function|Array} directiveFactory An injectable directive factory function. See - * {@link guide/directive} for more info. - * @returns {ng.$compileProvider} Self for chaining. - */ - this.directive = function registerDirective(name, directiveFactory) { - assertNotHasOwnProperty(name, 'directive'); - if (isString(name)) { - assertArg(directiveFactory, 'directiveFactory'); - if (!hasDirectives.hasOwnProperty(name)) { - hasDirectives[name] = []; - $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', - function($injector, $exceptionHandler) { - var directives = []; - forEach(hasDirectives[name], function(directiveFactory, index) { - try { - var directive = $injector.invoke(directiveFactory); - if (isFunction(directive)) { - directive = { compile: valueFn(directive) }; - } else if (!directive.compile && directive.link) { - directive.compile = valueFn(directive.link); - } - directive.priority = directive.priority || 0; - directive.index = index; - directive.name = directive.name || name; - directive.require = directive.require || (directive.controller && directive.name); - directive.restrict = directive.restrict || 'A'; - directives.push(directive); - } catch (e) { - $exceptionHandler(e); - } - }); - return directives; - }]); - } - hasDirectives[name].push(directiveFactory); - } else { - forEach(name, reverseParams(registerDirective)); - } - return this; - }; - - - /** - * @ngdoc method - * @name $compileProvider#aHrefSanitizationWhitelist - * @kind function - * - * @description - * Retrieves or overrides the default regular expression that is used for whitelisting of safe - * urls during a[href] sanitization. - * - * The sanitization is a security measure aimed at prevent XSS attacks via html links. - * - * Any url about to be assigned to a[href] via data-binding is first normalized and turned into - * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` - * regular expression. If a match is found, the original url is written into the dom. Otherwise, - * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. - * - * @param {RegExp=} regexp New regexp to whitelist urls with. - * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for - * chaining otherwise. - */ - this.aHrefSanitizationWhitelist = function(regexp) { - if (isDefined(regexp)) { - $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp); - return this; - } else { - return $$sanitizeUriProvider.aHrefSanitizationWhitelist(); - } - }; - - - /** - * @ngdoc method - * @name $compileProvider#imgSrcSanitizationWhitelist - * @kind function - * - * @description - * Retrieves or overrides the default regular expression that is used for whitelisting of safe - * urls during img[src] sanitization. - * - * The sanitization is a security measure aimed at prevent XSS attacks via html links. - * - * Any url about to be assigned to img[src] via data-binding is first normalized and turned into - * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` - * regular expression. If a match is found, the original url is written into the dom. Otherwise, - * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. - * - * @param {RegExp=} regexp New regexp to whitelist urls with. - * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for - * chaining otherwise. - */ - this.imgSrcSanitizationWhitelist = function(regexp) { - if (isDefined(regexp)) { - $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp); - return this; - } else { - return $$sanitizeUriProvider.imgSrcSanitizationWhitelist(); - } - }; - - this.$get = [ - '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse', - '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri', - function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse, - $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) { - - var Attributes = function(element, attr) { - this.$$element = element; - this.$attr = attr || {}; - }; - - Attributes.prototype = { - /** - * @ngdoc method - * @name $compile.directive.Attributes#$normalize - * @kind function - * - * @description - * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or - * `data-`) to its normalized, camelCase form. - * - * Also there is special case for Moz prefix starting with upper case letter. - * - * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} - * - * @param {string} name Name to normalize - */ - $normalize: directiveNormalize, - - - /** - * @ngdoc method - * @name $compile.directive.Attributes#$addClass - * @kind function - * - * @description - * Adds the CSS class value specified by the classVal parameter to the element. If animations - * are enabled then an animation will be triggered for the class addition. - * - * @param {string} classVal The className value that will be added to the element - */ - $addClass : function(classVal) { - if(classVal && classVal.length > 0) { - $animate.addClass(this.$$element, classVal); - } - }, - - /** - * @ngdoc method - * @name $compile.directive.Attributes#$removeClass - * @kind function - * - * @description - * Removes the CSS class value specified by the classVal parameter from the element. If - * animations are enabled then an animation will be triggered for the class removal. - * - * @param {string} classVal The className value that will be removed from the element - */ - $removeClass : function(classVal) { - if(classVal && classVal.length > 0) { - $animate.removeClass(this.$$element, classVal); - } - }, - - /** - * @ngdoc method - * @name $compile.directive.Attributes#$updateClass - * @kind function - * - * @description - * Adds and removes the appropriate CSS class values to the element based on the difference - * between the new and old CSS class values (specified as newClasses and oldClasses). - * - * @param {string} newClasses The current CSS className value - * @param {string} oldClasses The former CSS className value - */ - $updateClass : function(newClasses, oldClasses) { - var toAdd = tokenDifference(newClasses, oldClasses); - var toRemove = tokenDifference(oldClasses, newClasses); - - if(toAdd.length === 0) { - $animate.removeClass(this.$$element, toRemove); - } else if(toRemove.length === 0) { - $animate.addClass(this.$$element, toAdd); - } else { - $animate.setClass(this.$$element, toAdd, toRemove); - } - }, - - /** - * Set a normalized attribute on the element in a way such that all directives - * can share the attribute. This function properly handles boolean attributes. - * @param {string} key Normalized key. (ie ngAttribute) - * @param {string|boolean} value The value to set. If `null` attribute will be deleted. - * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. - * Defaults to true. - * @param {string=} attrName Optional none normalized name. Defaults to key. - */ - $set: function(key, value, writeAttr, attrName) { - // TODO: decide whether or not to throw an error if "class" - //is set through this function since it may cause $updateClass to - //become unstable. - - var booleanKey = getBooleanAttrName(this.$$element[0], key), - normalizedVal, - nodeName; - - if (booleanKey) { - this.$$element.prop(key, value); - attrName = booleanKey; - } - - this[key] = value; - - // translate normalized key to actual key - if (attrName) { - this.$attr[key] = attrName; - } else { - attrName = this.$attr[key]; - if (!attrName) { - this.$attr[key] = attrName = snake_case(key, '-'); - } - } - - nodeName = nodeName_(this.$$element); - - // sanitize a[href] and img[src] values - if ((nodeName === 'A' && key === 'href') || - (nodeName === 'IMG' && key === 'src')) { - this[key] = value = $$sanitizeUri(value, key === 'src'); - } - - if (writeAttr !== false) { - if (value === null || value === undefined) { - this.$$element.removeAttr(attrName); - } else { - this.$$element.attr(attrName, value); - } - } - - // fire observers - var $$observers = this.$$observers; - $$observers && forEach($$observers[key], function(fn) { - try { - fn(value); - } catch (e) { - $exceptionHandler(e); - } - }); - }, - - - /** - * @ngdoc method - * @name $compile.directive.Attributes#$observe - * @kind function - * - * @description - * Observes an interpolated attribute. - * - * The observer function will be invoked once during the next `$digest` following - * compilation. The observer is then invoked whenever the interpolated value - * changes. - * - * @param {string} key Normalized key. (ie ngAttribute) . - * @param {function(interpolatedValue)} fn Function that will be called whenever - the interpolated value of the attribute changes. - * See the {@link guide/directive#Attributes Directives} guide for more info. - * @returns {function()} the `fn` parameter. - */ - $observe: function(key, fn) { - var attrs = this, - $$observers = (attrs.$$observers || (attrs.$$observers = {})), - listeners = ($$observers[key] || ($$observers[key] = [])); - - listeners.push(fn); - $rootScope.$evalAsync(function() { - if (!listeners.$$inter) { - // no one registered attribute interpolation function, so lets call it manually - fn(attrs[key]); - } - }); - return fn; - } - }; - - var startSymbol = $interpolate.startSymbol(), - endSymbol = $interpolate.endSymbol(), - denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') - ? identity - : function denormalizeTemplate(template) { - return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); - }, - NG_ATTR_BINDING = /^ngAttr[A-Z]/; - - - return compile; - - //================================ - - function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, - previousCompileContext) { - if (!($compileNodes instanceof jqLite)) { - // jquery always rewraps, whereas we need to preserve the original selector so that we can - // modify it. - $compileNodes = jqLite($compileNodes); - } - // We can not compile top level text elements since text nodes can be merged and we will - // not be able to attach scope data to them, so we will wrap them in - forEach($compileNodes, function(node, index){ - if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) { - $compileNodes[index] = node = jqLite(node).wrap('').parent()[0]; - } - }); - var compositeLinkFn = - compileNodes($compileNodes, transcludeFn, $compileNodes, - maxPriority, ignoreDirective, previousCompileContext); - safeAddClass($compileNodes, 'ng-scope'); - return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn){ - assertArg(scope, 'scope'); - // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart - // and sometimes changes the structure of the DOM. - var $linkNode = cloneConnectFn - ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!! - : $compileNodes; - - forEach(transcludeControllers, function(instance, name) { - $linkNode.data('$' + name + 'Controller', instance); - }); - - // Attach scope only to non-text nodes. - for(var i = 0, ii = $linkNode.length; i - addDirective(directives, - directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective); - - // iterate over the attributes - for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes, - j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { - var attrStartName = false; - var attrEndName = false; - - attr = nAttrs[j]; - if (!msie || msie >= 8 || attr.specified) { - name = attr.name; - value = trim(attr.value); - - // support ngAttr attribute binding - ngAttrName = directiveNormalize(name); - if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) { - name = snake_case(ngAttrName.substr(6), '-'); - } - - var directiveNName = ngAttrName.replace(/(Start|End)$/, ''); - if (ngAttrName === directiveNName + 'Start') { - attrStartName = name; - attrEndName = name.substr(0, name.length - 5) + 'end'; - name = name.substr(0, name.length - 6); - } - - nName = directiveNormalize(name.toLowerCase()); - attrsMap[nName] = name; - if (isNgAttr || !attrs.hasOwnProperty(nName)) { - attrs[nName] = value; - if (getBooleanAttrName(node, nName)) { - attrs[nName] = true; // presence means true - } - } - addAttrInterpolateDirective(node, directives, value, nName); - addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, - attrEndName); - } - } - - // use class as directive - className = node.className; - if (isString(className) && className !== '') { - while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) { - nName = directiveNormalize(match[2]); - if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { - attrs[nName] = trim(match[3]); - } - className = className.substr(match.index + match[0].length); - } - } - break; - case 3: /* Text Node */ - addTextInterpolateDirective(directives, node.nodeValue); - break; - case 8: /* Comment */ - try { - match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); - if (match) { - nName = directiveNormalize(match[1]); - if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { - attrs[nName] = trim(match[2]); - } - } - } catch (e) { - // turns out that under some circumstances IE9 throws errors when one attempts to read - // comment's node value. - // Just ignore it and continue. (Can't seem to reproduce in test case.) - } - break; - } - - directives.sort(byPriority); - return directives; - } - - /** - * Given a node with an directive-start it collects all of the siblings until it finds - * directive-end. - * @param node - * @param attrStart - * @param attrEnd - * @returns {*} - */ - function groupScan(node, attrStart, attrEnd) { - var nodes = []; - var depth = 0; - if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { - var startNode = node; - do { - if (!node) { - throw $compileMinErr('uterdir', - "Unterminated attribute, found '{0}' but no matching '{1}' found.", - attrStart, attrEnd); - } - if (node.nodeType == 1 /** Element **/) { - if (node.hasAttribute(attrStart)) depth++; - if (node.hasAttribute(attrEnd)) depth--; - } - nodes.push(node); - node = node.nextSibling; - } while (depth > 0); - } else { - nodes.push(node); - } - - return jqLite(nodes); - } - - /** - * Wrapper for linking function which converts normal linking function into a grouped - * linking function. - * @param linkFn - * @param attrStart - * @param attrEnd - * @returns {Function} - */ - function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { - return function(scope, element, attrs, controllers, transcludeFn) { - element = groupScan(element[0], attrStart, attrEnd); - return linkFn(scope, element, attrs, controllers, transcludeFn); - }; - } - - /** - * Once the directives have been collected, their compile functions are executed. This method - * is responsible for inlining directive templates as well as terminating the application - * of the directives if the terminal directive has been reached. - * - * @param {Array} directives Array of collected directives to execute their compile function. - * this needs to be pre-sorted by priority order. - * @param {Node} compileNode The raw DOM node to apply the compile functions to - * @param {Object} templateAttrs The shared attribute function - * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the - * scope argument is auto-generated to the new - * child of the transcluded parent scope. - * @param {JQLite} jqCollection If we are working on the root of the compile tree then this - * argument has the root jqLite array so that we can replace nodes - * on it. - * @param {Object=} originalReplaceDirective An optional directive that will be ignored when - * compiling the transclusion. - * @param {Array.} preLinkFns - * @param {Array.} postLinkFns - * @param {Object} previousCompileContext Context used for previous compilation of the current - * node - * @returns {Function} linkFn - */ - function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, - jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, - previousCompileContext) { - previousCompileContext = previousCompileContext || {}; - - var terminalPriority = -Number.MAX_VALUE, - newScopeDirective, - controllerDirectives = previousCompileContext.controllerDirectives, - newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, - templateDirective = previousCompileContext.templateDirective, - nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, - hasTranscludeDirective = false, - hasTemplate = false, - hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective, - $compileNode = templateAttrs.$$element = jqLite(compileNode), - directive, - directiveName, - $template, - replaceDirective = originalReplaceDirective, - childTranscludeFn = transcludeFn, - linkFn, - directiveValue; - - // executes all directives on the current element - for(var i = 0, ii = directives.length; i < ii; i++) { - directive = directives[i]; - var attrStart = directive.$$start; - var attrEnd = directive.$$end; - - // collect multiblock sections - if (attrStart) { - $compileNode = groupScan(compileNode, attrStart, attrEnd); - } - $template = undefined; - - if (terminalPriority > directive.priority) { - break; // prevent further processing of directives - } - - if (directiveValue = directive.scope) { - newScopeDirective = newScopeDirective || directive; - - // skip the check for directives with async templates, we'll check the derived sync - // directive when the template arrives - if (!directive.templateUrl) { - assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, - $compileNode); - if (isObject(directiveValue)) { - newIsolateScopeDirective = directive; - } - } - } - - directiveName = directive.name; - - if (!directive.templateUrl && directive.controller) { - directiveValue = directive.controller; - controllerDirectives = controllerDirectives || {}; - assertNoDuplicate("'" + directiveName + "' controller", - controllerDirectives[directiveName], directive, $compileNode); - controllerDirectives[directiveName] = directive; - } - - if (directiveValue = directive.transclude) { - hasTranscludeDirective = true; - - // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. - // This option should only be used by directives that know how to safely handle element transclusion, - // where the transcluded nodes are added or replaced after linking. - if (!directive.$$tlb) { - assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); - nonTlbTranscludeDirective = directive; - } - - if (directiveValue == 'element') { - hasElementTranscludeDirective = true; - terminalPriority = directive.priority; - $template = $compileNode; - $compileNode = templateAttrs.$$element = - jqLite(document.createComment(' ' + directiveName + ': ' + - templateAttrs[directiveName] + ' ')); - compileNode = $compileNode[0]; - replaceWith(jqCollection, sliceArgs($template), compileNode); - - childTranscludeFn = compile($template, transcludeFn, terminalPriority, - replaceDirective && replaceDirective.name, { - // Don't pass in: - // - controllerDirectives - otherwise we'll create duplicates controllers - // - newIsolateScopeDirective or templateDirective - combining templates with - // element transclusion doesn't make sense. - // - // We need only nonTlbTranscludeDirective so that we prevent putting transclusion - // on the same element more than once. - nonTlbTranscludeDirective: nonTlbTranscludeDirective - }); - } else { - $template = jqLite(jqLiteClone(compileNode)).contents(); - $compileNode.empty(); // clear contents - childTranscludeFn = compile($template, transcludeFn); - } - } - - if (directive.template) { - hasTemplate = true; - assertNoDuplicate('template', templateDirective, directive, $compileNode); - templateDirective = directive; - - directiveValue = (isFunction(directive.template)) - ? directive.template($compileNode, templateAttrs) - : directive.template; - - directiveValue = denormalizeTemplate(directiveValue); - - if (directive.replace) { - replaceDirective = directive; - if (jqLiteIsTextNode(directiveValue)) { - $template = []; - } else { - $template = jqLite(trim(directiveValue)); - } - compileNode = $template[0]; - - if ($template.length != 1 || compileNode.nodeType !== 1) { - throw $compileMinErr('tplrt', - "Template for directive '{0}' must have exactly one root element. {1}", - directiveName, ''); - } - - replaceWith(jqCollection, $compileNode, compileNode); - - var newTemplateAttrs = {$attr: {}}; - - // combine directives from the original node and from the template: - // - take the array of directives for this element - // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) - // - collect directives from the template and sort them by priority - // - combine directives as: processed + template + unprocessed - var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); - var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); - - if (newIsolateScopeDirective) { - markDirectivesAsIsolate(templateDirectives); - } - directives = directives.concat(templateDirectives).concat(unprocessedDirectives); - mergeTemplateAttributes(templateAttrs, newTemplateAttrs); - - ii = directives.length; - } else { - $compileNode.html(directiveValue); - } - } - - if (directive.templateUrl) { - hasTemplate = true; - assertNoDuplicate('template', templateDirective, directive, $compileNode); - templateDirective = directive; - - if (directive.replace) { - replaceDirective = directive; - } - - nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, - templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, { - controllerDirectives: controllerDirectives, - newIsolateScopeDirective: newIsolateScopeDirective, - templateDirective: templateDirective, - nonTlbTranscludeDirective: nonTlbTranscludeDirective - }); - ii = directives.length; - } else if (directive.compile) { - try { - linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); - if (isFunction(linkFn)) { - addLinkFns(null, linkFn, attrStart, attrEnd); - } else if (linkFn) { - addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); - } - } catch (e) { - $exceptionHandler(e, startingTag($compileNode)); - } - } - - if (directive.terminal) { - nodeLinkFn.terminal = true; - terminalPriority = Math.max(terminalPriority, directive.priority); - } - - } - - nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; - nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective; - nodeLinkFn.templateOnThisElement = hasTemplate; - nodeLinkFn.transclude = childTranscludeFn; - - previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective; - - // might be normal or delayed nodeLinkFn depending on if templateUrl is present - return nodeLinkFn; - - //////////////////// - - function addLinkFns(pre, post, attrStart, attrEnd) { - if (pre) { - if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); - pre.require = directive.require; - pre.directiveName = directiveName; - if (newIsolateScopeDirective === directive || directive.$$isolateScope) { - pre = cloneAndAnnotateFn(pre, {isolateScope: true}); - } - preLinkFns.push(pre); - } - if (post) { - if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); - post.require = directive.require; - post.directiveName = directiveName; - if (newIsolateScopeDirective === directive || directive.$$isolateScope) { - post = cloneAndAnnotateFn(post, {isolateScope: true}); - } - postLinkFns.push(post); - } - } - - - function getControllers(directiveName, require, $element, elementControllers) { - var value, retrievalMethod = 'data', optional = false; - if (isString(require)) { - while((value = require.charAt(0)) == '^' || value == '?') { - require = require.substr(1); - if (value == '^') { - retrievalMethod = 'inheritedData'; - } - optional = optional || value == '?'; - } - value = null; - - if (elementControllers && retrievalMethod === 'data') { - value = elementControllers[require]; - } - value = value || $element[retrievalMethod]('$' + require + 'Controller'); - - if (!value && !optional) { - throw $compileMinErr('ctreq', - "Controller '{0}', required by directive '{1}', can't be found!", - require, directiveName); - } - return value; - } else if (isArray(require)) { - value = []; - forEach(require, function(require) { - value.push(getControllers(directiveName, require, $element, elementControllers)); - }); - } - return value; - } - - - function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { - var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn; - - attrs = (compileNode === linkNode) - ? templateAttrs - : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr)); - $element = attrs.$$element; - - if (newIsolateScopeDirective) { - var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/; - - isolateScope = scope.$new(true); - - if (templateDirective && (templateDirective === newIsolateScopeDirective || - templateDirective === newIsolateScopeDirective.$$originalDirective)) { - $element.data('$isolateScope', isolateScope); - } else { - $element.data('$isolateScopeNoTemplate', isolateScope); - } - - - - safeAddClass($element, 'ng-isolate-scope'); - - forEach(newIsolateScopeDirective.scope, function(definition, scopeName) { - var match = definition.match(LOCAL_REGEXP) || [], - attrName = match[3] || scopeName, - optional = (match[2] == '?'), - mode = match[1], // @, =, or & - lastValue, - parentGet, parentSet, compare; - - isolateScope.$$isolateBindings[scopeName] = mode + attrName; - - switch (mode) { - - case '@': - attrs.$observe(attrName, function(value) { - isolateScope[scopeName] = value; - }); - attrs.$$observers[attrName].$$scope = scope; - if( attrs[attrName] ) { - // If the attribute has been provided then we trigger an interpolation to ensure - // the value is there for use in the link fn - isolateScope[scopeName] = $interpolate(attrs[attrName])(scope); - } - break; - - case '=': - if (optional && !attrs[attrName]) { - return; - } - parentGet = $parse(attrs[attrName]); - if (parentGet.literal) { - compare = equals; - } else { - compare = function(a,b) { return a === b || (a !== a && b !== b); }; - } - parentSet = parentGet.assign || function() { - // reset the change, or we will throw this exception on every $digest - lastValue = isolateScope[scopeName] = parentGet(scope); - throw $compileMinErr('nonassign', - "Expression '{0}' used with directive '{1}' is non-assignable!", - attrs[attrName], newIsolateScopeDirective.name); - }; - lastValue = isolateScope[scopeName] = parentGet(scope); - isolateScope.$watch(function parentValueWatch() { - var parentValue = parentGet(scope); - if (!compare(parentValue, isolateScope[scopeName])) { - // we are out of sync and need to copy - if (!compare(parentValue, lastValue)) { - // parent changed and it has precedence - isolateScope[scopeName] = parentValue; - } else { - // if the parent can be assigned then do so - parentSet(scope, parentValue = isolateScope[scopeName]); - } - } - return lastValue = parentValue; - }, null, parentGet.literal); - break; - - case '&': - parentGet = $parse(attrs[attrName]); - isolateScope[scopeName] = function(locals) { - return parentGet(scope, locals); - }; - break; - - default: - throw $compileMinErr('iscp', - "Invalid isolate scope definition for directive '{0}'." + - " Definition: {... {1}: '{2}' ...}", - newIsolateScopeDirective.name, scopeName, definition); - } - }); - } - transcludeFn = boundTranscludeFn && controllersBoundTransclude; - if (controllerDirectives) { - forEach(controllerDirectives, function(directive) { - var locals = { - $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, - $element: $element, - $attrs: attrs, - $transclude: transcludeFn - }, controllerInstance; - - controller = directive.controller; - if (controller == '@') { - controller = attrs[directive.name]; - } - - controllerInstance = $controller(controller, locals); - // For directives with element transclusion the element is a comment, - // but jQuery .data doesn't support attaching data to comment nodes as it's hard to - // clean up (http://bugs.jquery.com/ticket/8335). - // Instead, we save the controllers for the element in a local hash and attach to .data - // later, once we have the actual element. - elementControllers[directive.name] = controllerInstance; - if (!hasElementTranscludeDirective) { - $element.data('$' + directive.name + 'Controller', controllerInstance); - } - - if (directive.controllerAs) { - locals.$scope[directive.controllerAs] = controllerInstance; - } - }); - } - - // PRELINKING - for(i = 0, ii = preLinkFns.length; i < ii; i++) { - try { - linkFn = preLinkFns[i]; - linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, - linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn); - } catch (e) { - $exceptionHandler(e, startingTag($element)); - } - } - - // RECURSION - // We only pass the isolate scope, if the isolate directive has a template, - // otherwise the child elements do not belong to the isolate directive. - var scopeToChild = scope; - if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) { - scopeToChild = isolateScope; - } - childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn); - - // POSTLINKING - for(i = postLinkFns.length - 1; i >= 0; i--) { - try { - linkFn = postLinkFns[i]; - linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, - linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn); - } catch (e) { - $exceptionHandler(e, startingTag($element)); - } - } - - // This is the function that is injected as `$transclude`. - function controllersBoundTransclude(scope, cloneAttachFn) { - var transcludeControllers; - - // no scope passed - if (arguments.length < 2) { - cloneAttachFn = scope; - scope = undefined; - } - - if (hasElementTranscludeDirective) { - transcludeControllers = elementControllers; - } - - return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers); - } - } - } - - function markDirectivesAsIsolate(directives) { - // mark all directives as needing isolate scope. - for (var j = 0, jj = directives.length; j < jj; j++) { - directives[j] = inherit(directives[j], {$$isolateScope: true}); - } - } - - /** - * looks up the directive and decorates it with exception handling and proper parameters. We - * call this the boundDirective. - * - * @param {string} name name of the directive to look up. - * @param {string} location The directive must be found in specific format. - * String containing any of theses characters: - * - * * `E`: element name - * * `A': attribute - * * `C`: class - * * `M`: comment - * @returns {boolean} true if directive was added. - */ - function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, - endAttrName) { - if (name === ignoreDirective) return null; - var match = null; - if (hasDirectives.hasOwnProperty(name)) { - for(var directive, directives = $injector.get(name + Suffix), - i = 0, ii = directives.length; i directive.priority) && - directive.restrict.indexOf(location) != -1) { - if (startAttrName) { - directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); - } - tDirectives.push(directive); - match = directive; - } - } catch(e) { $exceptionHandler(e); } - } - } - return match; - } - - - /** - * When the element is replaced with HTML template then the new attributes - * on the template need to be merged with the existing attributes in the DOM. - * The desired effect is to have both of the attributes present. - * - * @param {object} dst destination attributes (original DOM) - * @param {object} src source attributes (from the directive template) - */ - function mergeTemplateAttributes(dst, src) { - var srcAttr = src.$attr, - dstAttr = dst.$attr, - $element = dst.$$element; - - // reapply the old attributes to the new element - forEach(dst, function(value, key) { - if (key.charAt(0) != '$') { - if (src[key] && src[key] !== value) { - value += (key === 'style' ? ';' : ' ') + src[key]; - } - dst.$set(key, value, true, srcAttr[key]); - } - }); - - // copy the new attributes on the old attrs object - forEach(src, function(value, key) { - if (key == 'class') { - safeAddClass($element, value); - dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value; - } else if (key == 'style') { - $element.attr('style', $element.attr('style') + ';' + value); - dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value; - // `dst` will never contain hasOwnProperty as DOM parser won't let it. - // You will get an "InvalidCharacterError: DOM Exception 5" error if you - // have an attribute like "has-own-property" or "data-has-own-property", etc. - } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) { - dst[key] = value; - dstAttr[key] = srcAttr[key]; - } - }); - } - - - function compileTemplateUrl(directives, $compileNode, tAttrs, - $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) { - var linkQueue = [], - afterTemplateNodeLinkFn, - afterTemplateChildLinkFn, - beforeTemplateCompileNode = $compileNode[0], - origAsyncDirective = directives.shift(), - // The fact that we have to copy and patch the directive seems wrong! - derivedSyncDirective = extend({}, origAsyncDirective, { - templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective - }), - templateUrl = (isFunction(origAsyncDirective.templateUrl)) - ? origAsyncDirective.templateUrl($compileNode, tAttrs) - : origAsyncDirective.templateUrl; - - $compileNode.empty(); - - $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}). - success(function(content) { - var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; - - content = denormalizeTemplate(content); - - if (origAsyncDirective.replace) { - if (jqLiteIsTextNode(content)) { - $template = []; - } else { - $template = jqLite(trim(content)); - } - compileNode = $template[0]; - - if ($template.length != 1 || compileNode.nodeType !== 1) { - throw $compileMinErr('tplrt', - "Template for directive '{0}' must have exactly one root element. {1}", - origAsyncDirective.name, templateUrl); - } - - tempTemplateAttrs = {$attr: {}}; - replaceWith($rootElement, $compileNode, compileNode); - var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs); - - if (isObject(origAsyncDirective.scope)) { - markDirectivesAsIsolate(templateDirectives); - } - directives = templateDirectives.concat(directives); - mergeTemplateAttributes(tAttrs, tempTemplateAttrs); - } else { - compileNode = beforeTemplateCompileNode; - $compileNode.html(content); - } - - directives.unshift(derivedSyncDirective); - - afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, - childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, - previousCompileContext); - forEach($rootElement, function(node, i) { - if (node == compileNode) { - $rootElement[i] = $compileNode[0]; - } - }); - afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); - - while(linkQueue.length) { - var scope = linkQueue.shift(), - beforeTemplateLinkNode = linkQueue.shift(), - linkRootElement = linkQueue.shift(), - boundTranscludeFn = linkQueue.shift(), - linkNode = $compileNode[0]; - - if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { - var oldClasses = beforeTemplateLinkNode.className; - - if (!(previousCompileContext.hasElementTranscludeDirective && - origAsyncDirective.replace)) { - // it was cloned therefore we have to clone as well. - linkNode = jqLiteClone(compileNode); - } - - replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); - - // Copy in CSS classes from original node - safeAddClass(jqLite(linkNode), oldClasses); - } - if (afterTemplateNodeLinkFn.transcludeOnThisElement) { - childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); - } else { - childBoundTranscludeFn = boundTranscludeFn; - } - afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, - childBoundTranscludeFn); - } - linkQueue = null; - }). - error(function(response, code, headers, config) { - throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url); - }); - - return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { - var childBoundTranscludeFn = boundTranscludeFn; - if (linkQueue) { - linkQueue.push(scope); - linkQueue.push(node); - linkQueue.push(rootElement); - linkQueue.push(childBoundTranscludeFn); - } else { - if (afterTemplateNodeLinkFn.transcludeOnThisElement) { - childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); - } - afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn); - } - }; - } - - - /** - * Sorting function for bound directives. - */ - function byPriority(a, b) { - var diff = b.priority - a.priority; - if (diff !== 0) return diff; - if (a.name !== b.name) return (a.name < b.name) ? -1 : 1; - return a.index - b.index; - } - - - function assertNoDuplicate(what, previousDirective, directive, element) { - if (previousDirective) { - throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}', - previousDirective.name, directive.name, what, startingTag(element)); - } - } - - - function addTextInterpolateDirective(directives, text) { - var interpolateFn = $interpolate(text, true); - if (interpolateFn) { - directives.push({ - priority: 0, - compile: function textInterpolateCompileFn(templateNode) { - // when transcluding a template that has bindings in the root - // then we don't have a parent and should do this in the linkFn - var parent = templateNode.parent(), hasCompileParent = parent.length; - if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding'); - - return function textInterpolateLinkFn(scope, node) { - var parent = node.parent(), - bindings = parent.data('$binding') || []; - bindings.push(interpolateFn); - parent.data('$binding', bindings); - if (!hasCompileParent) safeAddClass(parent, 'ng-binding'); - scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { - node[0].nodeValue = value; - }); - }; - } - }); - } - } - - - function getTrustedContext(node, attrNormalizedName) { - if (attrNormalizedName == "srcdoc") { - return $sce.HTML; - } - var tag = nodeName_(node); - // maction[xlink:href] can source SVG. It's not limited to . - if (attrNormalizedName == "xlinkHref" || - (tag == "FORM" && attrNormalizedName == "action") || - (tag != "IMG" && (attrNormalizedName == "src" || - attrNormalizedName == "ngSrc"))) { - return $sce.RESOURCE_URL; - } - } - - - function addAttrInterpolateDirective(node, directives, value, name) { - var interpolateFn = $interpolate(value, true); - - // no interpolation found -> ignore - if (!interpolateFn) return; - - - if (name === "multiple" && nodeName_(node) === "SELECT") { - throw $compileMinErr("selmulti", - "Binding to the 'multiple' attribute is not supported. Element: {0}", - startingTag(node)); - } - - directives.push({ - priority: 100, - compile: function() { - return { - pre: function attrInterpolatePreLinkFn(scope, element, attr) { - var $$observers = (attr.$$observers || (attr.$$observers = {})); - - if (EVENT_HANDLER_ATTR_REGEXP.test(name)) { - throw $compileMinErr('nodomevents', - "Interpolations for HTML DOM event attributes are disallowed. Please use the " + - "ng- versions (such as ng-click instead of onclick) instead."); - } - - // we need to interpolate again, in case the attribute value has been updated - // (e.g. by another directive's compile function) - interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name)); - - // if attribute was updated so that there is no interpolation going on we don't want to - // register any observers - if (!interpolateFn) return; - - // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the - // actual attr value - attr[name] = interpolateFn(scope); - ($$observers[name] || ($$observers[name] = [])).$$inter = true; - (attr.$$observers && attr.$$observers[name].$$scope || scope). - $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) { - //special case for class attribute addition + removal - //so that class changes can tap into the animation - //hooks provided by the $animate service. Be sure to - //skip animations when the first digest occurs (when - //both the new and the old values are the same) since - //the CSS classes are the non-interpolated values - if(name === 'class' && newValue != oldValue) { - attr.$updateClass(newValue, oldValue); - } else { - attr.$set(name, newValue); - } - }); - } - }; - } - }); - } - - - /** - * This is a special jqLite.replaceWith, which can replace items which - * have no parents, provided that the containing jqLite collection is provided. - * - * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes - * in the root of the tree. - * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep - * the shell, but replace its DOM node reference. - * @param {Node} newNode The new DOM node. - */ - function replaceWith($rootElement, elementsToRemove, newNode) { - var firstElementToRemove = elementsToRemove[0], - removeCount = elementsToRemove.length, - parent = firstElementToRemove.parentNode, - i, ii; - - if ($rootElement) { - for(i = 0, ii = $rootElement.length; i < ii; i++) { - if ($rootElement[i] == firstElementToRemove) { - $rootElement[i++] = newNode; - for (var j = i, j2 = j + removeCount - 1, - jj = $rootElement.length; - j < jj; j++, j2++) { - if (j2 < jj) { - $rootElement[j] = $rootElement[j2]; - } else { - delete $rootElement[j]; - } - } - $rootElement.length -= removeCount - 1; - break; - } - } - } - - if (parent) { - parent.replaceChild(newNode, firstElementToRemove); - } - var fragment = document.createDocumentFragment(); - fragment.appendChild(firstElementToRemove); - newNode[jqLite.expando] = firstElementToRemove[jqLite.expando]; - for (var k = 1, kk = elementsToRemove.length; k < kk; k++) { - var element = elementsToRemove[k]; - jqLite(element).remove(); // must do this way to clean up expando - fragment.appendChild(element); - delete elementsToRemove[k]; - } - - elementsToRemove[0] = newNode; - elementsToRemove.length = 1; - } - - - function cloneAndAnnotateFn(fn, annotation) { - return extend(function() { return fn.apply(null, arguments); }, fn, annotation); - } - }]; -} - -var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i; -/** - * Converts all accepted directives format into proper directive name. - * @param name Name to normalize - */ -function directiveNormalize(name) { - return camelCase(name.replace(PREFIX_REGEXP, '')); -} - -/** - * @ngdoc type - * @name $compile.directive.Attributes - * - * @description - * A shared object between directive compile / linking functions which contains normalized DOM - * element attributes. The values reflect current binding state `{{ }}`. The normalization is - * needed since all of these are treated as equivalent in Angular: - * - * ``` - * - * ``` - */ - -/** - * @ngdoc property - * @name $compile.directive.Attributes#$attr - * - * @description - * A map of DOM element attribute names to the normalized name. This is - * needed to do reverse lookup from normalized name back to actual name. - */ - - -/** - * @ngdoc method - * @name $compile.directive.Attributes#$set - * @kind function - * - * @description - * Set DOM element attribute value. - * - * - * @param {string} name Normalized element attribute name of the property to modify. The name is - * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr} - * property to the original name. - * @param {string} value Value to set the attribute to. The value can be an interpolated string. - */ - - - -/** - * Closure compiler type information - */ - -function nodesetLinkingFn( - /* angular.Scope */ scope, - /* NodeList */ nodeList, - /* Element */ rootElement, - /* function(Function) */ boundTranscludeFn -){} - -function directiveLinkingFn( - /* nodesetLinkingFn */ nodesetLinkingFn, - /* angular.Scope */ scope, - /* Node */ node, - /* Element */ rootElement, - /* function(Function) */ boundTranscludeFn -){} - -function tokenDifference(str1, str2) { - var values = '', - tokens1 = str1.split(/\s+/), - tokens2 = str2.split(/\s+/); - - outer: - for(var i = 0; i < tokens1.length; i++) { - var token = tokens1[i]; - for(var j = 0; j < tokens2.length; j++) { - if(token == tokens2[j]) continue outer; - } - values += (values.length > 0 ? ' ' : '') + token; - } - return values; -} - -/** - * @ngdoc provider - * @name $controllerProvider - * @description - * The {@link ng.$controller $controller service} is used by Angular to create new - * controllers. - * - * This provider allows controller registration via the - * {@link ng.$controllerProvider#register register} method. - */ -function $ControllerProvider() { - var controllers = {}, - CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; - - - /** - * @ngdoc method - * @name $controllerProvider#register - * @param {string|Object} name Controller name, or an object map of controllers where the keys are - * the names and the values are the constructors. - * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI - * annotations in the array notation). - */ - this.register = function(name, constructor) { - assertNotHasOwnProperty(name, 'controller'); - if (isObject(name)) { - extend(controllers, name); - } else { - controllers[name] = constructor; - } - }; - - - this.$get = ['$injector', '$window', function($injector, $window) { - - /** - * @ngdoc service - * @name $controller - * @requires $injector - * - * @param {Function|string} constructor If called with a function then it's considered to be the - * controller constructor function. Otherwise it's considered to be a string which is used - * to retrieve the controller constructor using the following steps: - * - * * check if a controller with given name is registered via `$controllerProvider` - * * check if evaluating the string on the current scope returns a constructor - * * check `window[constructor]` on the global `window` object - * - * @param {Object} locals Injection locals for Controller. - * @return {Object} Instance of given controller. - * - * @description - * `$controller` service is responsible for instantiating controllers. - * - * It's just a simple call to {@link auto.$injector $injector}, but extracted into - * a service, so that one can override this service with [BC version](https://gist.github.com/1649788). - */ - return function(expression, locals) { - var instance, match, constructor, identifier; - - if(isString(expression)) { - match = expression.match(CNTRL_REG), - constructor = match[1], - identifier = match[3]; - expression = controllers.hasOwnProperty(constructor) - ? controllers[constructor] - : getter(locals.$scope, constructor, true) || getter($window, constructor, true); - - assertArgFn(expression, constructor, true); - } - - instance = $injector.instantiate(expression, locals); - - if (identifier) { - if (!(locals && typeof locals.$scope === 'object')) { - throw minErr('$controller')('noscp', - "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", - constructor || expression.name, identifier); - } - - locals.$scope[identifier] = instance; - } - - return instance; - }; - }]; -} - -/** - * @ngdoc service - * @name $document - * @requires $window - * - * @description - * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object. - * - * @example - - -
-

$document title:

-

window.document title:

-
-
- - angular.module('documentExample', []) - .controller('ExampleController', ['$scope', '$document', function($scope, $document) { - $scope.title = $document[0].title; - $scope.windowTitle = angular.element(window.document)[0].title; - }]); - -
- */ -function $DocumentProvider(){ - this.$get = ['$window', function(window){ - return jqLite(window.document); - }]; -} - -/** - * @ngdoc service - * @name $exceptionHandler - * @requires ng.$log - * - * @description - * Any uncaught exception in angular expressions is delegated to this service. - * The default implementation simply delegates to `$log.error` which logs it into - * the browser console. - * - * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by - * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing. - * - * ## Example: - * - * ```js - * angular.module('exceptionOverride', []).factory('$exceptionHandler', function () { - * return function (exception, cause) { - * exception.message += ' (caused by "' + cause + '")'; - * throw exception; - * }; - * }); - * ``` - * - * This example will override the normal action of `$exceptionHandler`, to make angular - * exceptions fail hard when they happen, instead of just logging to the console. - * - * @param {Error} exception Exception associated with the error. - * @param {string=} cause optional information about the context in which - * the error was thrown. - * - */ -function $ExceptionHandlerProvider() { - this.$get = ['$log', function($log) { - return function(exception, cause) { - $log.error.apply($log, arguments); - }; - }]; -} - -/** - * Parse headers into key value object - * - * @param {string} headers Raw headers as a string - * @returns {Object} Parsed headers as key value object - */ -function parseHeaders(headers) { - var parsed = {}, key, val, i; - - if (!headers) return parsed; - - forEach(headers.split('\n'), function(line) { - i = line.indexOf(':'); - key = lowercase(trim(line.substr(0, i))); - val = trim(line.substr(i + 1)); - - if (key) { - parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; - } - }); - - return parsed; -} - - -/** - * Returns a function that provides access to parsed headers. - * - * Headers are lazy parsed when first requested. - * @see parseHeaders - * - * @param {(string|Object)} headers Headers to provide access to. - * @returns {function(string=)} Returns a getter function which if called with: - * - * - if called with single an argument returns a single header value or null - * - if called with no arguments returns an object containing all headers. - */ -function headersGetter(headers) { - var headersObj = isObject(headers) ? headers : undefined; - - return function(name) { - if (!headersObj) headersObj = parseHeaders(headers); - - if (name) { - return headersObj[lowercase(name)] || null; - } - - return headersObj; - }; -} - - -/** - * Chain all given functions - * - * This function is used for both request and response transforming - * - * @param {*} data Data to transform. - * @param {function(string=)} headers Http headers getter fn. - * @param {(Function|Array.)} fns Function or an array of functions. - * @returns {*} Transformed data. - */ -function transformData(data, headers, fns) { - if (isFunction(fns)) - return fns(data, headers); - - forEach(fns, function(fn) { - data = fn(data, headers); - }); - - return data; -} - - -function isSuccess(status) { - return 200 <= status && status < 300; -} - - -/** - * @ngdoc provider - * @name $httpProvider - * @description - * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. - * */ -function $HttpProvider() { - var JSON_START = /^\s*(\[|\{[^\{])/, - JSON_END = /[\}\]]\s*$/, - PROTECTION_PREFIX = /^\)\]\}',?\n/, - CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'}; - - /** - * @ngdoc property - * @name $httpProvider#defaults - * @description - * - * Object containing default values for all {@link ng.$http $http} requests. - * - * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. - * Defaults value is `'XSRF-TOKEN'`. - * - * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the - * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. - * - * - **`defaults.headers`** - {Object} - Default headers for all $http requests. - * Refer to {@link ng.$http#setting-http-headers $http} for documentation on - * setting default headers. - * - **`defaults.headers.common`** - * - **`defaults.headers.post`** - * - **`defaults.headers.put`** - * - **`defaults.headers.patch`** - **/ - var defaults = this.defaults = { - // transform incoming response data - transformResponse: [function(data) { - if (isString(data)) { - // strip json vulnerability protection prefix - data = data.replace(PROTECTION_PREFIX, ''); - if (JSON_START.test(data) && JSON_END.test(data)) - data = fromJson(data); - } - return data; - }], - - // transform outgoing request data - transformRequest: [function(d) { - return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d; - }], - - // default headers - headers: { - common: { - 'Accept': 'application/json, text/plain, */*' - }, - post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), - put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), - patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON) - }, - - xsrfCookieName: 'XSRF-TOKEN', - xsrfHeaderName: 'X-XSRF-TOKEN' - }; - - /** - * @ngdoc property - * @name $httpProvider#interceptors - * @description - * - * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http} - * pre-processing of request or postprocessing of responses. - * - * These service factories are ordered by request, i.e. they are applied in the same order as the - * array, on request, but reverse order, on response. - * - * {@link ng.$http#interceptors Interceptors detailed info} - **/ - var interceptorFactories = this.interceptors = []; - - /** - * For historical reasons, response interceptors are ordered by the order in which - * they are applied to the response. (This is the opposite of interceptorFactories) - */ - var responseInterceptorFactories = this.responseInterceptors = []; - - this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', - function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) { - - var defaultCache = $cacheFactory('$http'); - - /** - * Interceptors stored in reverse order. Inner interceptors before outer interceptors. - * The reversal is needed so that we can build up the interception chain around the - * server request. - */ - var reversedInterceptors = []; - - forEach(interceptorFactories, function(interceptorFactory) { - reversedInterceptors.unshift(isString(interceptorFactory) - ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); - }); - - forEach(responseInterceptorFactories, function(interceptorFactory, index) { - var responseFn = isString(interceptorFactory) - ? $injector.get(interceptorFactory) - : $injector.invoke(interceptorFactory); - - /** - * Response interceptors go before "around" interceptors (no real reason, just - * had to pick one.) But they are already reversed, so we can't use unshift, hence - * the splice. - */ - reversedInterceptors.splice(index, 0, { - response: function(response) { - return responseFn($q.when(response)); - }, - responseError: function(response) { - return responseFn($q.reject(response)); - } - }); - }); - - - /** - * @ngdoc service - * @kind function - * @name $http - * @requires ng.$httpBackend - * @requires $cacheFactory - * @requires $rootScope - * @requires $q - * @requires $injector - * - * @description - * The `$http` service is a core Angular service that facilitates communication with the remote - * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) - * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). - * - * For unit testing applications that use `$http` service, see - * {@link ngMock.$httpBackend $httpBackend mock}. - * - * For a higher level of abstraction, please check out the {@link ngResource.$resource - * $resource} service. - * - * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by - * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage - * it is important to familiarize yourself with these APIs and the guarantees they provide. - * - * - * # General usage - * The `$http` service is a function which takes a single argument — a configuration object — - * that is used to generate an HTTP request and returns a {@link ng.$q promise} - * with two $http specific methods: `success` and `error`. - * - * ```js - * $http({method: 'GET', url: '/someUrl'}). - * success(function(data, status, headers, config) { - * // this callback will be called asynchronously - * // when the response is available - * }). - * error(function(data, status, headers, config) { - * // called asynchronously if an error occurs - * // or server returns response with an error status. - * }); - * ``` - * - * Since the returned value of calling the $http function is a `promise`, you can also use - * the `then` method to register callbacks, and these callbacks will receive a single argument – - * an object representing the response. See the API signature and type info below for more - * details. - * - * A response status code between 200 and 299 is considered a success status and - * will result in the success callback being called. Note that if the response is a redirect, - * XMLHttpRequest will transparently follow it, meaning that the error callback will not be - * called for such responses. - * - * # Writing Unit Tests that use $http - * When unit testing (using {@link ngMock ngMock}), it is necessary to call - * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending - * request using trained responses. - * - * ``` - * $httpBackend.expectGET(...); - * $http.get(...); - * $httpBackend.flush(); - * ``` - * - * # Shortcut methods - * - * Shortcut methods are also available. All shortcut methods require passing in the URL, and - * request data must be passed in for POST/PUT requests. - * - * ```js - * $http.get('/someUrl').success(successCallback); - * $http.post('/someUrl', data).success(successCallback); - * ``` - * - * Complete list of shortcut methods: - * - * - {@link ng.$http#get $http.get} - * - {@link ng.$http#head $http.head} - * - {@link ng.$http#post $http.post} - * - {@link ng.$http#put $http.put} - * - {@link ng.$http#delete $http.delete} - * - {@link ng.$http#jsonp $http.jsonp} - * - {@link ng.$http#patch $http.patch} - * - * - * # Setting HTTP Headers - * - * The $http service will automatically add certain HTTP headers to all requests. These defaults - * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration - * object, which currently contains this default configuration: - * - * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): - * - `Accept: application/json, text/plain, * / *` - * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) - * - `Content-Type: application/json` - * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) - * - `Content-Type: application/json` - * - * To add or overwrite these defaults, simply add or remove a property from these configuration - * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object - * with the lowercased HTTP method name as the key, e.g. - * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. - * - * The defaults can also be set at runtime via the `$http.defaults` object in the same - * fashion. For example: - * - * ``` - * module.run(function($http) { - * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w' - * }); - * ``` - * - * In addition, you can supply a `headers` property in the config object passed when - * calling `$http(config)`, which overrides the defaults without changing them globally. - * - * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, - * Use the `headers` property, setting the desired header to `undefined`. For example: - * - * ```js - * var req = { - * method: 'POST', - * url: 'http://example.com', - * headers: { - * 'Content-Type': undefined - * }, - * data: { test: 'test' }, - * } - * - * $http(req).success(function(){...}).error(function(){...}); - * ``` - * - * # Transforming Requests and Responses - * - * Both requests and responses can be transformed using transform functions. By default, Angular - * applies these transformations: - * - * Request transformations: - * - * - If the `data` property of the request configuration object contains an object, serialize it - * into JSON format. - * - * Response transformations: - * - * - If XSRF prefix is detected, strip it (see Security Considerations section below). - * - If JSON response is detected, deserialize it using a JSON parser. - * - * To globally augment or override the default transforms, modify the - * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse` - * properties. These properties are by default an array of transform functions, which allows you - * to `push` or `unshift` a new transformation function into the transformation chain. You can - * also decide to completely override any default transformations by assigning your - * transformation functions to these properties directly without the array wrapper. These defaults - * are again available on the $http factory at run-time, which may be useful if you have run-time - * services you wish to be involved in your transformations. - * - * Similarly, to locally override the request/response transforms, augment the - * `transformRequest` and/or `transformResponse` properties of the configuration object passed - * into `$http`. - * - * - * # Caching - * - * To enable caching, set the request configuration `cache` property to `true` (to use default - * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). - * When the cache is enabled, `$http` stores the response from the server in the specified - * cache. The next time the same request is made, the response is served from the cache without - * sending a request to the server. - * - * Note that even if the response is served from cache, delivery of the data is asynchronous in - * the same way that real requests are. - * - * If there are multiple GET requests for the same URL that should be cached using the same - * cache, but the cache is not populated yet, only one request to the server will be made and - * the remaining requests will be fulfilled using the response from the first request. - * - * You can change the default cache to a new object (built with - * {@link ng.$cacheFactory `$cacheFactory`}) by updating the - * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set - * their `cache` property to `true` will now use this cache object. - * - * If you set the default cache to `false` then only requests that specify their own custom - * cache object will be cached. - * - * # Interceptors - * - * Before you start creating interceptors, be sure to understand the - * {@link ng.$q $q and deferred/promise APIs}. - * - * For purposes of global error handling, authentication, or any kind of synchronous or - * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be - * able to intercept requests before they are handed to the server and - * responses before they are handed over to the application code that - * initiated these requests. The interceptors leverage the {@link ng.$q - * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing. - * - * The interceptors are service factories that are registered with the `$httpProvider` by - * adding them to the `$httpProvider.interceptors` array. The factory is called and - * injected with dependencies (if specified) and returns the interceptor. - * - * There are two kinds of interceptors (and two kinds of rejection interceptors): - * - * * `request`: interceptors get called with a http `config` object. The function is free to - * modify the `config` object or create a new one. The function needs to return the `config` - * object directly, or a promise containing the `config` or a new `config` object. - * * `requestError`: interceptor gets called when a previous interceptor threw an error or - * resolved with a rejection. - * * `response`: interceptors get called with http `response` object. The function is free to - * modify the `response` object or create a new one. The function needs to return the `response` - * object directly, or as a promise containing the `response` or a new `response` object. - * * `responseError`: interceptor gets called when a previous interceptor threw an error or - * resolved with a rejection. - * - * - * ```js - * // register the interceptor as a service - * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { - * return { - * // optional method - * 'request': function(config) { - * // do something on success - * return config; - * }, - * - * // optional method - * 'requestError': function(rejection) { - * // do something on error - * if (canRecover(rejection)) { - * return responseOrNewPromise - * } - * return $q.reject(rejection); - * }, - * - * - * - * // optional method - * 'response': function(response) { - * // do something on success - * return response; - * }, - * - * // optional method - * 'responseError': function(rejection) { - * // do something on error - * if (canRecover(rejection)) { - * return responseOrNewPromise - * } - * return $q.reject(rejection); - * } - * }; - * }); - * - * $httpProvider.interceptors.push('myHttpInterceptor'); - * - * - * // alternatively, register the interceptor via an anonymous factory - * $httpProvider.interceptors.push(function($q, dependency1, dependency2) { - * return { - * 'request': function(config) { - * // same as above - * }, - * - * 'response': function(response) { - * // same as above - * } - * }; - * }); - * ``` - * - * # Response interceptors (DEPRECATED) - * - * Before you start creating interceptors, be sure to understand the - * {@link ng.$q $q and deferred/promise APIs}. - * - * For purposes of global error handling, authentication or any kind of synchronous or - * asynchronous preprocessing of received responses, it is desirable to be able to intercept - * responses for http requests before they are handed over to the application code that - * initiated these requests. The response interceptors leverage the {@link ng.$q - * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing. - * - * The interceptors are service factories that are registered with the $httpProvider by - * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and - * injected with dependencies (if specified) and returns the interceptor — a function that - * takes a {@link ng.$q promise} and returns the original or a new promise. - * - * ```js - * // register the interceptor as a service - * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { - * return function(promise) { - * return promise.then(function(response) { - * // do something on success - * return response; - * }, function(response) { - * // do something on error - * if (canRecover(response)) { - * return responseOrNewPromise - * } - * return $q.reject(response); - * }); - * } - * }); - * - * $httpProvider.responseInterceptors.push('myHttpInterceptor'); - * - * - * // register the interceptor via an anonymous factory - * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) { - * return function(promise) { - * // same as above - * } - * }); - * ``` - * - * - * # Security Considerations - * - * When designing web applications, consider security threats from: - * - * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) - * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) - * - * Both server and the client must cooperate in order to eliminate these threats. Angular comes - * pre-configured with strategies that address these issues, but for this to work backend server - * cooperation is required. - * - * ## JSON Vulnerability Protection - * - * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) - * allows third party website to turn your JSON resource URL into - * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To - * counter this your server can prefix all JSON requests with following string `")]}',\n"`. - * Angular will automatically strip the prefix before processing it as JSON. - * - * For example if your server needs to return: - * ```js - * ['one','two'] - * ``` - * - * which is vulnerable to attack, your server can return: - * ```js - * )]}', - * ['one','two'] - * ``` - * - * Angular will strip the prefix, before processing the JSON. - * - * - * ## Cross Site Request Forgery (XSRF) Protection - * - * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which - * an unauthorized site can gain your user's private data. Angular provides a mechanism - * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie - * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only - * JavaScript that runs on your domain could read the cookie, your server can be assured that - * the XHR came from JavaScript running on your domain. The header will not be set for - * cross-domain requests. - * - * To take advantage of this, your server needs to set a token in a JavaScript readable session - * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the - * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure - * that only JavaScript running on your domain could have sent the request. The token must be - * unique for each user and must be verifiable by the server (to prevent the JavaScript from - * making up its own tokens). We recommend that the token is a digest of your site's - * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) - * for added security. - * - * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName - * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, - * or the per-request config object. - * - * - * @param {object} config Object describing the request to be made and how it should be - * processed. The object has following properties: - * - * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) - * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. - * - **params** – `{Object.}` – Map of strings or objects which will be turned - * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be - * JSONified. - * - **data** – `{string|Object}` – Data to be sent as the request message data. - * - **headers** – `{Object}` – Map of strings or functions which return strings representing - * HTTP headers to send to the server. If the return value of a function is null, the - * header will not be sent. - * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. - * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. - * - **transformRequest** – - * `{function(data, headersGetter)|Array.}` – - * transform function or an array of such functions. The transform function takes the http - * request body and headers and returns its transformed (typically serialized) version. - * - **transformResponse** – - * `{function(data, headersGetter)|Array.}` – - * transform function or an array of such functions. The transform function takes the http - * response body and headers and returns its transformed (typically deserialized) version. - * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the - * GET request, otherwise if a cache instance built with - * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for - * caching. - * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} - * that should abort the request when resolved. - * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the - * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) - * for more information. - * - **responseType** - `{string}` - see - * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). - * - * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the - * standard `then` method and two http specific methods: `success` and `error`. The `then` - * method takes two arguments a success and an error callback which will be called with a - * response object. The `success` and `error` methods take a single argument - a function that - * will be called when the request succeeds or fails respectively. The arguments passed into - * these functions are destructured representation of the response object passed into the - * `then` method. The response object has these properties: - * - * - **data** – `{string|Object}` – The response body transformed with the transform - * functions. - * - **status** – `{number}` – HTTP status code of the response. - * - **headers** – `{function([headerName])}` – Header getter function. - * - **config** – `{Object}` – The configuration object that was used to generate the request. - * - **statusText** – `{string}` – HTTP status text of the response. - * - * @property {Array.} pendingRequests Array of config objects for currently pending - * requests. This is primarily meant to be used for debugging purposes. - * - * - * @example - - -
- - -
- - - -
http status code: {{status}}
-
http response data: {{data}}
-
-
- - angular.module('httpExample', []) - .controller('FetchController', ['$scope', '$http', '$templateCache', - function($scope, $http, $templateCache) { - $scope.method = 'GET'; - $scope.url = 'http-hello.html'; - - $scope.fetch = function() { - $scope.code = null; - $scope.response = null; - - $http({method: $scope.method, url: $scope.url, cache: $templateCache}). - success(function(data, status) { - $scope.status = status; - $scope.data = data; - }). - error(function(data, status) { - $scope.data = data || "Request failed"; - $scope.status = status; - }); - }; - - $scope.updateModel = function(method, url) { - $scope.method = method; - $scope.url = url; - }; - }]); - - - Hello, $http! - - - var status = element(by.binding('status')); - var data = element(by.binding('data')); - var fetchBtn = element(by.id('fetchbtn')); - var sampleGetBtn = element(by.id('samplegetbtn')); - var sampleJsonpBtn = element(by.id('samplejsonpbtn')); - var invalidJsonpBtn = element(by.id('invalidjsonpbtn')); - - it('should make an xhr GET request', function() { - sampleGetBtn.click(); - fetchBtn.click(); - expect(status.getText()).toMatch('200'); - expect(data.getText()).toMatch(/Hello, \$http!/); - }); - -// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185 -// it('should make a JSONP request to angularjs.org', function() { -// sampleJsonpBtn.click(); -// fetchBtn.click(); -// expect(status.getText()).toMatch('200'); -// expect(data.getText()).toMatch(/Super Hero!/); -// }); - - it('should make JSONP request to invalid URL and invoke the error handler', - function() { - invalidJsonpBtn.click(); - fetchBtn.click(); - expect(status.getText()).toMatch('0'); - expect(data.getText()).toMatch('Request failed'); - }); - -
- */ - function $http(requestConfig) { - var config = { - method: 'get', - transformRequest: defaults.transformRequest, - transformResponse: defaults.transformResponse - }; - var headers = mergeHeaders(requestConfig); - - extend(config, requestConfig); - config.headers = headers; - config.method = uppercase(config.method); - - var serverRequest = function(config) { - headers = config.headers; - var reqData = transformData(config.data, headersGetter(headers), config.transformRequest); - - // strip content-type if data is undefined - if (isUndefined(reqData)) { - forEach(headers, function(value, header) { - if (lowercase(header) === 'content-type') { - delete headers[header]; - } - }); - } - - if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) { - config.withCredentials = defaults.withCredentials; - } - - // send request - return sendReq(config, reqData, headers).then(transformResponse, transformResponse); - }; - - var chain = [serverRequest, undefined]; - var promise = $q.when(config); - - // apply interceptors - forEach(reversedInterceptors, function(interceptor) { - if (interceptor.request || interceptor.requestError) { - chain.unshift(interceptor.request, interceptor.requestError); - } - if (interceptor.response || interceptor.responseError) { - chain.push(interceptor.response, interceptor.responseError); - } - }); - - while(chain.length) { - var thenFn = chain.shift(); - var rejectFn = chain.shift(); - - promise = promise.then(thenFn, rejectFn); - } - - promise.success = function(fn) { - promise.then(function(response) { - fn(response.data, response.status, response.headers, config); - }); - return promise; - }; - - promise.error = function(fn) { - promise.then(null, function(response) { - fn(response.data, response.status, response.headers, config); - }); - return promise; - }; - - return promise; - - function transformResponse(response) { - // make a copy since the response must be cacheable - var resp = extend({}, response, { - data: transformData(response.data, response.headers, config.transformResponse) - }); - return (isSuccess(response.status)) - ? resp - : $q.reject(resp); - } - - function mergeHeaders(config) { - var defHeaders = defaults.headers, - reqHeaders = extend({}, config.headers), - defHeaderName, lowercaseDefHeaderName, reqHeaderName; - - defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]); - - // using for-in instead of forEach to avoid unecessary iteration after header has been found - defaultHeadersIteration: - for (defHeaderName in defHeaders) { - lowercaseDefHeaderName = lowercase(defHeaderName); - - for (reqHeaderName in reqHeaders) { - if (lowercase(reqHeaderName) === lowercaseDefHeaderName) { - continue defaultHeadersIteration; - } - } - - reqHeaders[defHeaderName] = defHeaders[defHeaderName]; - } - - // execute if header value is a function for merged headers - execHeaders(reqHeaders); - return reqHeaders; - - function execHeaders(headers) { - var headerContent; - - forEach(headers, function(headerFn, header) { - if (isFunction(headerFn)) { - headerContent = headerFn(); - if (headerContent != null) { - headers[header] = headerContent; - } else { - delete headers[header]; - } - } - }); - } - } - } - - $http.pendingRequests = []; - - /** - * @ngdoc method - * @name $http#get - * - * @description - * Shortcut method to perform `GET` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - - /** - * @ngdoc method - * @name $http#delete - * - * @description - * Shortcut method to perform `DELETE` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - - /** - * @ngdoc method - * @name $http#head - * - * @description - * Shortcut method to perform `HEAD` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - - /** - * @ngdoc method - * @name $http#jsonp - * - * @description - * Shortcut method to perform `JSONP` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request. - * The name of the callback should be the string `JSON_CALLBACK`. - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - createShortMethods('get', 'delete', 'head', 'jsonp'); - - /** - * @ngdoc method - * @name $http#post - * - * @description - * Shortcut method to perform `POST` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - - /** - * @ngdoc method - * @name $http#put - * - * @description - * Shortcut method to perform `PUT` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - - /** - * @ngdoc method - * @name $http#patch - * - * @description - * Shortcut method to perform `PATCH` request. - * - * @param {string} url Relative or absolute URL specifying the destination of the request - * @param {*} data Request content - * @param {Object=} config Optional configuration object - * @returns {HttpPromise} Future object - */ - createShortMethodsWithData('post', 'put', 'patch'); - - /** - * @ngdoc property - * @name $http#defaults - * - * @description - * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of - * default headers, withCredentials as well as request and response transformations. - * - * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above. - */ - $http.defaults = defaults; - - - return $http; - - - function createShortMethods(names) { - forEach(arguments, function(name) { - $http[name] = function(url, config) { - return $http(extend(config || {}, { - method: name, - url: url - })); - }; - }); - } - - - function createShortMethodsWithData(name) { - forEach(arguments, function(name) { - $http[name] = function(url, data, config) { - return $http(extend(config || {}, { - method: name, - url: url, - data: data - })); - }; - }); - } - - - /** - * Makes the request. - * - * !!! ACCESSES CLOSURE VARS: - * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests - */ - function sendReq(config, reqData, reqHeaders) { - var deferred = $q.defer(), - promise = deferred.promise, - cache, - cachedResp, - url = buildUrl(config.url, config.params); - - $http.pendingRequests.push(config); - promise.then(removePendingReq, removePendingReq); - - - if ((config.cache || defaults.cache) && config.cache !== false && - (config.method === 'GET' || config.method === 'JSONP')) { - cache = isObject(config.cache) ? config.cache - : isObject(defaults.cache) ? defaults.cache - : defaultCache; - } - - if (cache) { - cachedResp = cache.get(url); - if (isDefined(cachedResp)) { - if (isPromiseLike(cachedResp)) { - // cached request has already been sent, but there is no response yet - cachedResp.then(removePendingReq, removePendingReq); - return cachedResp; - } else { - // serving from cache - if (isArray(cachedResp)) { - resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]); - } else { - resolvePromise(cachedResp, 200, {}, 'OK'); - } - } - } else { - // put the promise for the non-transformed response into cache as a placeholder - cache.put(url, promise); - } - } - - - // if we won't have the response in cache, set the xsrf headers and - // send the request to the backend - if (isUndefined(cachedResp)) { - var xsrfValue = urlIsSameOrigin(config.url) - ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName] - : undefined; - if (xsrfValue) { - reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; - } - - $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, - config.withCredentials, config.responseType); - } - - return promise; - - - /** - * Callback registered to $httpBackend(): - * - caches the response if desired - * - resolves the raw $http promise - * - calls $apply - */ - function done(status, response, headersString, statusText) { - if (cache) { - if (isSuccess(status)) { - cache.put(url, [status, response, parseHeaders(headersString), statusText]); - } else { - // remove promise from the cache - cache.remove(url); - } - } - - resolvePromise(response, status, headersString, statusText); - if (!$rootScope.$$phase) $rootScope.$apply(); - } - - - /** - * Resolves the raw $http promise. - */ - function resolvePromise(response, status, headers, statusText) { - // normalize internal statuses to 0 - status = Math.max(status, 0); - - (isSuccess(status) ? deferred.resolve : deferred.reject)({ - data: response, - status: status, - headers: headersGetter(headers), - config: config, - statusText : statusText - }); - } - - - function removePendingReq() { - var idx = indexOf($http.pendingRequests, config); - if (idx !== -1) $http.pendingRequests.splice(idx, 1); - } - } - - - function buildUrl(url, params) { - if (!params) return url; - var parts = []; - forEachSorted(params, function(value, key) { - if (value === null || isUndefined(value)) return; - if (!isArray(value)) value = [value]; - - forEach(value, function(v) { - if (isObject(v)) { - if (isDate(v)){ - v = v.toISOString(); - } else { - v = toJson(v); - } - } - parts.push(encodeUriQuery(key) + '=' + - encodeUriQuery(v)); - }); - }); - if(parts.length > 0) { - url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&'); - } - return url; - } - }]; -} - -function createXhr(method) { - //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest - //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest - //if it is available - if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) || - !window.XMLHttpRequest)) { - return new window.ActiveXObject("Microsoft.XMLHTTP"); - } else if (window.XMLHttpRequest) { - return new window.XMLHttpRequest(); - } - - throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest."); -} - -/** - * @ngdoc service - * @name $httpBackend - * @requires $window - * @requires $document - * - * @description - * HTTP backend used by the {@link ng.$http service} that delegates to - * XMLHttpRequest object or JSONP and deals with browser incompatibilities. - * - * You should never need to use this service directly, instead use the higher-level abstractions: - * {@link ng.$http $http} or {@link ngResource.$resource $resource}. - * - * During testing this implementation is swapped with {@link ngMock.$httpBackend mock - * $httpBackend} which can be trained with responses. - */ -function $HttpBackendProvider() { - this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { - return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]); - }]; -} - -function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { - var ABORTED = -1; - - // TODO(vojta): fix the signature - return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { - var status; - $browser.$$incOutstandingRequestCount(); - url = url || $browser.url(); - - if (lowercase(method) == 'jsonp') { - var callbackId = '_' + (callbacks.counter++).toString(36); - callbacks[callbackId] = function(data) { - callbacks[callbackId].data = data; - callbacks[callbackId].called = true; - }; - - var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), - callbackId, function(status, text) { - completeRequest(callback, status, callbacks[callbackId].data, "", text); - callbacks[callbackId] = noop; - }); - } else { - - var xhr = createXhr(method); - - xhr.open(method, url, true); - forEach(headers, function(value, key) { - if (isDefined(value)) { - xhr.setRequestHeader(key, value); - } - }); - - // In IE6 and 7, this might be called synchronously when xhr.send below is called and the - // response is in the cache. the promise api will ensure that to the app code the api is - // always async - xhr.onreadystatechange = function() { - // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by - // xhrs that are resolved while the app is in the background (see #5426). - // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before - // continuing - // - // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and - // Safari respectively. - if (xhr && xhr.readyState == 4) { - var responseHeaders = null, - response = null, - statusText = ''; - - if(status !== ABORTED) { - responseHeaders = xhr.getAllResponseHeaders(); - - // responseText is the old-school way of retrieving response (supported by IE8 & 9) - // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) - response = ('response' in xhr) ? xhr.response : xhr.responseText; - } - - // Accessing statusText on an aborted xhr object will - // throw an 'c00c023f error' in IE9 and lower, don't touch it. - if (!(status === ABORTED && msie < 10)) { - statusText = xhr.statusText; - } - - completeRequest(callback, - status || xhr.status, - response, - responseHeaders, - statusText); - } - }; - - if (withCredentials) { - xhr.withCredentials = true; - } - - if (responseType) { - try { - xhr.responseType = responseType; - } catch (e) { - // WebKit added support for the json responseType value on 09/03/2013 - // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are - // known to throw when setting the value "json" as the response type. Other older - // browsers implementing the responseType - // - // The json response type can be ignored if not supported, because JSON payloads are - // parsed on the client-side regardless. - if (responseType !== 'json') { - throw e; - } - } - } - - xhr.send(post || null); - } - - if (timeout > 0) { - var timeoutId = $browserDefer(timeoutRequest, timeout); - } else if (isPromiseLike(timeout)) { - timeout.then(timeoutRequest); - } - - - function timeoutRequest() { - status = ABORTED; - jsonpDone && jsonpDone(); - xhr && xhr.abort(); - } - - function completeRequest(callback, status, response, headersString, statusText) { - // cancel timeout and subsequent timeout promise resolution - timeoutId && $browserDefer.cancel(timeoutId); - jsonpDone = xhr = null; - - // fix status code when it is 0 (0 status is undocumented). - // Occurs when accessing file resources or on Android 4.1 stock browser - // while retrieving files from application cache. - if (status === 0) { - status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0; - } - - // normalize IE bug (http://bugs.jquery.com/ticket/1450) - status = status === 1223 ? 204 : status; - statusText = statusText || ''; - - callback(status, response, headersString, statusText); - $browser.$$completeOutstandingRequest(noop); - } - }; - - function jsonpReq(url, callbackId, done) { - // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.: - // - fetches local scripts via XHR and evals them - // - adds and immediately removes script elements from the document - var script = rawDocument.createElement('script'), callback = null; - script.type = "text/javascript"; - script.src = url; - script.async = true; - - callback = function(event) { - removeEventListenerFn(script, "load", callback); - removeEventListenerFn(script, "error", callback); - rawDocument.body.removeChild(script); - script = null; - var status = -1; - var text = "unknown"; - - if (event) { - if (event.type === "load" && !callbacks[callbackId].called) { - event = { type: "error" }; - } - text = event.type; - status = event.type === "error" ? 404 : 200; - } - - if (done) { - done(status, text); - } - }; - - addEventListenerFn(script, "load", callback); - addEventListenerFn(script, "error", callback); - - if (msie <= 8) { - script.onreadystatechange = function() { - if (isString(script.readyState) && /loaded|complete/.test(script.readyState)) { - script.onreadystatechange = null; - callback({ - type: 'load' - }); - } - }; - } - - rawDocument.body.appendChild(script); - return callback; - } -} - -var $interpolateMinErr = minErr('$interpolate'); - -/** - * @ngdoc provider - * @name $interpolateProvider - * @kind function - * - * @description - * - * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. - * - * @example - - - -
- //demo.label// -
-
- - it('should interpolate binding with custom symbols', function() { - expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.'); - }); - -
- */ -function $InterpolateProvider() { - var startSymbol = '{{'; - var endSymbol = '}}'; - - /** - * @ngdoc method - * @name $interpolateProvider#startSymbol - * @description - * Symbol to denote start of expression in the interpolated string. Defaults to `{{`. - * - * @param {string=} value new value to set the starting symbol to. - * @returns {string|self} Returns the symbol when used as getter and self if used as setter. - */ - this.startSymbol = function(value){ - if (value) { - startSymbol = value; - return this; - } else { - return startSymbol; - } - }; - - /** - * @ngdoc method - * @name $interpolateProvider#endSymbol - * @description - * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. - * - * @param {string=} value new value to set the ending symbol to. - * @returns {string|self} Returns the symbol when used as getter and self if used as setter. - */ - this.endSymbol = function(value){ - if (value) { - endSymbol = value; - return this; - } else { - return endSymbol; - } - }; - - - this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) { - var startSymbolLength = startSymbol.length, - endSymbolLength = endSymbol.length; - - /** - * @ngdoc service - * @name $interpolate - * @kind function - * - * @requires $parse - * @requires $sce - * - * @description - * - * Compiles a string with markup into an interpolation function. This service is used by the - * HTML {@link ng.$compile $compile} service for data binding. See - * {@link ng.$interpolateProvider $interpolateProvider} for configuring the - * interpolation markup. - * - * - * ```js - * var $interpolate = ...; // injected - * var exp = $interpolate('Hello {{name | uppercase}}!'); - * expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!'); - * ``` - * - * - * @param {string} text The text with markup to interpolate. - * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have - * embedded expression in order to return an interpolation function. Strings with no - * embedded expression will return null for the interpolation function. - * @param {string=} trustedContext when provided, the returned function passes the interpolated - * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult, - * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that - * provides Strict Contextual Escaping for details. - * @returns {function(context)} an interpolation function which is used to compute the - * interpolated string. The function has these parameters: - * - * * `context`: an object against which any expressions embedded in the strings are evaluated - * against. - * - */ - function $interpolate(text, mustHaveExpression, trustedContext) { - var startIndex, - endIndex, - index = 0, - parts = [], - length = text.length, - hasInterpolation = false, - fn, - exp, - concat = []; - - while(index < length) { - if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) && - ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) { - (index != startIndex) && parts.push(text.substring(index, startIndex)); - parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex))); - fn.exp = exp; - index = endIndex + endSymbolLength; - hasInterpolation = true; - } else { - // we did not find anything, so we have to add the remainder to the parts array - (index != length) && parts.push(text.substring(index)); - index = length; - } - } - - if (!(length = parts.length)) { - // we added, nothing, must have been an empty string. - parts.push(''); - length = 1; - } - - // Concatenating expressions makes it hard to reason about whether some combination of - // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a - // single expression be used for iframe[src], object[src], etc., we ensure that the value - // that's used is assigned or constructed by some JS code somewhere that is more testable or - // make it obvious that you bound the value to some user controlled value. This helps reduce - // the load when auditing for XSS issues. - if (trustedContext && parts.length > 1) { - throw $interpolateMinErr('noconcat', - "Error while interpolating: {0}\nStrict Contextual Escaping disallows " + - "interpolations that concatenate multiple expressions when a trusted value is " + - "required. See http://docs.angularjs.org/api/ng.$sce", text); - } - - if (!mustHaveExpression || hasInterpolation) { - concat.length = length; - fn = function(context) { - try { - for(var i = 0, ii = length, part; i - * **Note**: Intervals created by this service must be explicitly destroyed when you are finished - * with them. In particular they are not automatically destroyed when a controller's scope or a - * directive's element are destroyed. - * You should take this into consideration and make sure to always cancel the interval at the - * appropriate moment. See the example below for more details on how and when to do this. - * - * - * @param {function()} fn A function that should be called repeatedly. - * @param {number} delay Number of milliseconds between each function call. - * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat - * indefinitely. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @returns {promise} A promise which will be notified on each iteration. - * - * @example - * - * - * - * - *
- *
- * Date format:
- * Current time is: - *
- * Blood 1 : {{blood_1}} - * Blood 2 : {{blood_2}} - * - * - * - *
- *
- * - *
- *
- */ - function interval(fn, delay, count, invokeApply) { - var setInterval = $window.setInterval, - clearInterval = $window.clearInterval, - deferred = $q.defer(), - promise = deferred.promise, - iteration = 0, - skipApply = (isDefined(invokeApply) && !invokeApply); - - count = isDefined(count) ? count : 0; - - promise.then(null, null, fn); - - promise.$$intervalId = setInterval(function tick() { - deferred.notify(iteration++); - - if (count > 0 && iteration >= count) { - deferred.resolve(iteration); - clearInterval(promise.$$intervalId); - delete intervals[promise.$$intervalId]; - } - - if (!skipApply) $rootScope.$apply(); - - }, delay); - - intervals[promise.$$intervalId] = deferred; - - return promise; - } - - - /** - * @ngdoc method - * @name $interval#cancel - * - * @description - * Cancels a task associated with the `promise`. - * - * @param {promise} promise returned by the `$interval` function. - * @returns {boolean} Returns `true` if the task was successfully canceled. - */ - interval.cancel = function(promise) { - if (promise && promise.$$intervalId in intervals) { - intervals[promise.$$intervalId].reject('canceled'); - $window.clearInterval(promise.$$intervalId); - delete intervals[promise.$$intervalId]; - return true; - } - return false; - }; - - return interval; - }]; -} - -/** - * @ngdoc service - * @name $locale - * - * @description - * $locale service provides localization rules for various Angular components. As of right now the - * only public api is: - * - * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) - */ -function $LocaleProvider(){ - this.$get = function() { - return { - id: 'en-us', - - NUMBER_FORMATS: { - DECIMAL_SEP: '.', - GROUP_SEP: ',', - PATTERNS: [ - { // Decimal Pattern - minInt: 1, - minFrac: 0, - maxFrac: 3, - posPre: '', - posSuf: '', - negPre: '-', - negSuf: '', - gSize: 3, - lgSize: 3 - },{ //Currency Pattern - minInt: 1, - minFrac: 2, - maxFrac: 2, - posPre: '\u00A4', - posSuf: '', - negPre: '(\u00A4', - negSuf: ')', - gSize: 3, - lgSize: 3 - } - ], - CURRENCY_SYM: '$' - }, - - DATETIME_FORMATS: { - MONTH: - 'January,February,March,April,May,June,July,August,September,October,November,December' - .split(','), - SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), - DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), - SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','), - AMPMS: ['AM','PM'], - medium: 'MMM d, y h:mm:ss a', - short: 'M/d/yy h:mm a', - fullDate: 'EEEE, MMMM d, y', - longDate: 'MMMM d, y', - mediumDate: 'MMM d, y', - shortDate: 'M/d/yy', - mediumTime: 'h:mm:ss a', - shortTime: 'h:mm a' - }, - - pluralCat: function(num) { - if (num === 1) { - return 'one'; - } - return 'other'; - } - }; - }; -} - -var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, - DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; -var $locationMinErr = minErr('$location'); - - -/** - * Encode path using encodeUriSegment, ignoring forward slashes - * - * @param {string} path Path to encode - * @returns {string} - */ -function encodePath(path) { - var segments = path.split('/'), - i = segments.length; - - while (i--) { - segments[i] = encodeUriSegment(segments[i]); - } - - return segments.join('/'); -} - -function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) { - var parsedUrl = urlResolve(absoluteUrl, appBase); - - locationObj.$$protocol = parsedUrl.protocol; - locationObj.$$host = parsedUrl.hostname; - locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null; -} - - -function parseAppUrl(relativeUrl, locationObj, appBase) { - var prefixed = (relativeUrl.charAt(0) !== '/'); - if (prefixed) { - relativeUrl = '/' + relativeUrl; - } - var match = urlResolve(relativeUrl, appBase); - locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? - match.pathname.substring(1) : match.pathname); - locationObj.$$search = parseKeyValue(match.search); - locationObj.$$hash = decodeURIComponent(match.hash); - - // make sure path starts with '/'; - if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') { - locationObj.$$path = '/' + locationObj.$$path; - } -} - - -/** - * - * @param {string} begin - * @param {string} whole - * @returns {string} returns text from whole after begin or undefined if it does not begin with - * expected string. - */ -function beginsWith(begin, whole) { - if (whole.indexOf(begin) === 0) { - return whole.substr(begin.length); - } -} - - -function stripHash(url) { - var index = url.indexOf('#'); - return index == -1 ? url : url.substr(0, index); -} - - -function stripFile(url) { - return url.substr(0, stripHash(url).lastIndexOf('/') + 1); -} - -/* return the server only (scheme://host:port) */ -function serverBase(url) { - return url.substring(0, url.indexOf('/', url.indexOf('//') + 2)); -} - - -/** - * LocationHtml5Url represents an url - * This object is exposed as $location service when HTML5 mode is enabled and supported - * - * @constructor - * @param {string} appBase application base URL - * @param {string} basePrefix url path prefix - */ -function LocationHtml5Url(appBase, basePrefix) { - this.$$html5 = true; - basePrefix = basePrefix || ''; - var appBaseNoFile = stripFile(appBase); - parseAbsoluteUrl(appBase, this, appBase); - - - /** - * Parse given html5 (regular) url string into properties - * @param {string} newAbsoluteUrl HTML5 url - * @private - */ - this.$$parse = function(url) { - var pathUrl = beginsWith(appBaseNoFile, url); - if (!isString(pathUrl)) { - throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, - appBaseNoFile); - } - - parseAppUrl(pathUrl, this, appBase); - - if (!this.$$path) { - this.$$path = '/'; - } - - this.$$compose(); - }; - - /** - * Compose url and update `absUrl` property - * @private - */ - this.$$compose = function() { - var search = toKeyValue(this.$$search), - hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; - - this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; - this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/' - }; - - this.$$parseLinkUrl = function(url, relHref) { - var appUrl, prevAppUrl; - var rewrittenUrl; - - if ( (appUrl = beginsWith(appBase, url)) !== undefined ) { - prevAppUrl = appUrl; - if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) { - rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl); - } else { - rewrittenUrl = appBase + prevAppUrl; - } - } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) { - rewrittenUrl = appBaseNoFile + appUrl; - } else if (appBaseNoFile == url + '/') { - rewrittenUrl = appBaseNoFile; - } - if (rewrittenUrl) { - this.$$parse(rewrittenUrl); - } - return !!rewrittenUrl; - }; -} - - -/** - * LocationHashbangUrl represents url - * This object is exposed as $location service when developer doesn't opt into html5 mode. - * It also serves as the base class for html5 mode fallback on legacy browsers. - * - * @constructor - * @param {string} appBase application base URL - * @param {string} hashPrefix hashbang prefix - */ -function LocationHashbangUrl(appBase, hashPrefix) { - var appBaseNoFile = stripFile(appBase); - - parseAbsoluteUrl(appBase, this, appBase); - - - /** - * Parse given hashbang url into properties - * @param {string} url Hashbang url - * @private - */ - this.$$parse = function(url) { - var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); - var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' - ? beginsWith(hashPrefix, withoutBaseUrl) - : (this.$$html5) - ? withoutBaseUrl - : ''; - - if (!isString(withoutHashUrl)) { - throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, - hashPrefix); - } - parseAppUrl(withoutHashUrl, this, appBase); - - this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); - - this.$$compose(); - - /* - * In Windows, on an anchor node on documents loaded from - * the filesystem, the browser will return a pathname - * prefixed with the drive name ('/C:/path') when a - * pathname without a drive is set: - * * a.setAttribute('href', '/foo') - * * a.pathname === '/C:/foo' //true - * - * Inside of Angular, we're always using pathnames that - * do not include drive names for routing. - */ - function removeWindowsDriveName (path, url, base) { - /* - Matches paths for file protocol on windows, - such as /C:/foo/bar, and captures only /foo/bar. - */ - var windowsFilePathExp = /^\/[A-Z]:(\/.*)/; - - var firstPathSegmentMatch; - - //Get the relative path from the input URL. - if (url.indexOf(base) === 0) { - url = url.replace(base, ''); - } - - // The input URL intentionally contains a first path segment that ends with a colon. - if (windowsFilePathExp.exec(url)) { - return path; - } - - firstPathSegmentMatch = windowsFilePathExp.exec(path); - return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; - } - }; - - /** - * Compose hashbang url and update `absUrl` property - * @private - */ - this.$$compose = function() { - var search = toKeyValue(this.$$search), - hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; - - this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; - this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : ''); - }; - - this.$$parseLinkUrl = function(url, relHref) { - if(stripHash(appBase) == stripHash(url)) { - this.$$parse(url); - return true; - } - return false; - }; -} - - -/** - * LocationHashbangUrl represents url - * This object is exposed as $location service when html5 history api is enabled but the browser - * does not support it. - * - * @constructor - * @param {string} appBase application base URL - * @param {string} hashPrefix hashbang prefix - */ -function LocationHashbangInHtml5Url(appBase, hashPrefix) { - this.$$html5 = true; - LocationHashbangUrl.apply(this, arguments); - - var appBaseNoFile = stripFile(appBase); - - this.$$parseLinkUrl = function(url, relHref) { - var rewrittenUrl; - var appUrl; - - if ( appBase == stripHash(url) ) { - rewrittenUrl = url; - } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) { - rewrittenUrl = appBase + hashPrefix + appUrl; - } else if ( appBaseNoFile === url + '/') { - rewrittenUrl = appBaseNoFile; - } - if (rewrittenUrl) { - this.$$parse(rewrittenUrl); - } - return !!rewrittenUrl; - }; - - this.$$compose = function() { - var search = toKeyValue(this.$$search), - hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; - - this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; - // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#' - this.$$absUrl = appBase + hashPrefix + this.$$url; - }; - -} - - -LocationHashbangInHtml5Url.prototype = - LocationHashbangUrl.prototype = - LocationHtml5Url.prototype = { - - /** - * Are we in html5 mode? - * @private - */ - $$html5: false, - - /** - * Has any change been replacing ? - * @private - */ - $$replace: false, - - /** - * @ngdoc method - * @name $location#absUrl - * - * @description - * This method is getter only. - * - * Return full url representation with all segments encoded according to rules specified in - * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). - * - * @return {string} full url - */ - absUrl: locationGetter('$$absUrl'), - - /** - * @ngdoc method - * @name $location#url - * - * @description - * This method is getter / setter. - * - * Return url (e.g. `/path?a=b#hash`) when called without any parameter. - * - * Change path, search and hash, when called with parameter and return `$location`. - * - * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`) - * @return {string} url - */ - url: function(url) { - if (isUndefined(url)) - return this.$$url; - - var match = PATH_MATCH.exec(url); - if (match[1]) this.path(decodeURIComponent(match[1])); - if (match[2] || match[1]) this.search(match[3] || ''); - this.hash(match[5] || ''); - - return this; - }, - - /** - * @ngdoc method - * @name $location#protocol - * - * @description - * This method is getter only. - * - * Return protocol of current url. - * - * @return {string} protocol of current url - */ - protocol: locationGetter('$$protocol'), - - /** - * @ngdoc method - * @name $location#host - * - * @description - * This method is getter only. - * - * Return host of current url. - * - * @return {string} host of current url. - */ - host: locationGetter('$$host'), - - /** - * @ngdoc method - * @name $location#port - * - * @description - * This method is getter only. - * - * Return port of current url. - * - * @return {Number} port - */ - port: locationGetter('$$port'), - - /** - * @ngdoc method - * @name $location#path - * - * @description - * This method is getter / setter. - * - * Return path of current url when called without any parameter. - * - * Change path when called with parameter and return `$location`. - * - * Note: Path should always begin with forward slash (/), this method will add the forward slash - * if it is missing. - * - * @param {(string|number)=} path New path - * @return {string} path - */ - path: locationGetterSetter('$$path', function(path) { - path = path !== null ? path.toString() : ''; - return path.charAt(0) == '/' ? path : '/' + path; - }), - - /** - * @ngdoc method - * @name $location#search - * - * @description - * This method is getter / setter. - * - * Return search part (as object) of current url when called without any parameter. - * - * Change search part when called with parameter and return `$location`. - * - * - * ```js - * // given url http://example.com/#/some/path?foo=bar&baz=xoxo - * var searchObject = $location.search(); - * // => {foo: 'bar', baz: 'xoxo'} - * - * - * // set foo to 'yipee' - * $location.search('foo', 'yipee'); - * // => $location - * ``` - * - * @param {string|Object.|Object.>} search New search params - string or - * hash object. - * - * When called with a single argument the method acts as a setter, setting the `search` component - * of `$location` to the specified value. - * - * If the argument is a hash object containing an array of values, these values will be encoded - * as duplicate search parameters in the url. - * - * @param {(string|Number|Array|boolean)=} paramValue If `search` is a string or number, then `paramValue` - * will override only a single search property. - * - * If `paramValue` is an array, it will override the property of the `search` component of - * `$location` specified via the first argument. - * - * If `paramValue` is `null`, the property specified via the first argument will be deleted. - * - * If `paramValue` is `true`, the property specified via the first argument will be added with no - * value nor trailing equal sign. - * - * @return {Object} If called with no arguments returns the parsed `search` object. If called with - * one or more arguments returns `$location` object itself. - */ - search: function(search, paramValue) { - switch (arguments.length) { - case 0: - return this.$$search; - case 1: - if (isString(search) || isNumber(search)) { - search = search.toString(); - this.$$search = parseKeyValue(search); - } else if (isObject(search)) { - // remove object undefined or null properties - forEach(search, function(value, key) { - if (value == null) delete search[key]; - }); - - this.$$search = search; - } else { - throw $locationMinErr('isrcharg', - 'The first argument of the `$location#search()` call must be a string or an object.'); - } - break; - default: - if (isUndefined(paramValue) || paramValue === null) { - delete this.$$search[search]; - } else { - this.$$search[search] = paramValue; - } - } - - this.$$compose(); - return this; - }, - - /** - * @ngdoc method - * @name $location#hash - * - * @description - * This method is getter / setter. - * - * Return hash fragment when called without any parameter. - * - * Change hash fragment when called with parameter and return `$location`. - * - * @param {(string|number)=} hash New hash fragment - * @return {string} hash - */ - hash: locationGetterSetter('$$hash', function(hash) { - return hash !== null ? hash.toString() : ''; - }), - - /** - * @ngdoc method - * @name $location#replace - * - * @description - * If called, all changes to $location during current `$digest` will be replacing current history - * record, instead of adding new one. - */ - replace: function() { - this.$$replace = true; - return this; - } -}; - -function locationGetter(property) { - return function() { - return this[property]; - }; -} - - -function locationGetterSetter(property, preprocess) { - return function(value) { - if (isUndefined(value)) - return this[property]; - - this[property] = preprocess(value); - this.$$compose(); - - return this; - }; -} - - -/** - * @ngdoc service - * @name $location - * - * @requires $rootElement - * - * @description - * The $location service parses the URL in the browser address bar (based on the - * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL - * available to your application. Changes to the URL in the address bar are reflected into - * $location service and changes to $location are reflected into the browser address bar. - * - * **The $location service:** - * - * - Exposes the current URL in the browser address bar, so you can - * - Watch and observe the URL. - * - Change the URL. - * - Synchronizes the URL with the browser when the user - * - Changes the address bar. - * - Clicks the back or forward button (or clicks a History link). - * - Clicks on a link. - * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash). - * - * For more information see {@link guide/$location Developer Guide: Using $location} - */ - -/** - * @ngdoc provider - * @name $locationProvider - * @description - * Use the `$locationProvider` to configure how the application deep linking paths are stored. - */ -function $LocationProvider(){ - var hashPrefix = '', - html5Mode = false; - - /** - * @ngdoc method - * @name $locationProvider#hashPrefix - * @description - * @param {string=} prefix Prefix for hash part (containing path and search) - * @returns {*} current value if used as getter or itself (chaining) if used as setter - */ - this.hashPrefix = function(prefix) { - if (isDefined(prefix)) { - hashPrefix = prefix; - return this; - } else { - return hashPrefix; - } - }; - - /** - * @ngdoc method - * @name $locationProvider#html5Mode - * @description - * @param {boolean=} mode Use HTML5 strategy if available. - * @returns {*} current value if used as getter or itself (chaining) if used as setter - */ - this.html5Mode = function(mode) { - if (isDefined(mode)) { - html5Mode = mode; - return this; - } else { - return html5Mode; - } - }; - - /** - * @ngdoc event - * @name $location#$locationChangeStart - * @eventType broadcast on root scope - * @description - * Broadcasted before a URL will change. This change can be prevented by calling - * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more - * details about event object. Upon successful change - * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired. - * - * @param {Object} angularEvent Synthetic event object. - * @param {string} newUrl New URL - * @param {string=} oldUrl URL that was before it was changed. - */ - - /** - * @ngdoc event - * @name $location#$locationChangeSuccess - * @eventType broadcast on root scope - * @description - * Broadcasted after a URL was changed. - * - * @param {Object} angularEvent Synthetic event object. - * @param {string} newUrl New URL - * @param {string=} oldUrl URL that was before it was changed. - */ - - this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', - function( $rootScope, $browser, $sniffer, $rootElement) { - var $location, - LocationMode, - baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' - initialUrl = $browser.url(), - appBase; - - if (html5Mode) { - appBase = serverBase(initialUrl) + (baseHref || '/'); - LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url; - } else { - appBase = stripHash(initialUrl); - LocationMode = LocationHashbangUrl; - } - $location = new LocationMode(appBase, '#' + hashPrefix); - $location.$$parseLinkUrl(initialUrl, initialUrl); - - var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i; - - $rootElement.on('click', function(event) { - // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) - // currently we open nice url link and redirect then - - if (event.ctrlKey || event.metaKey || event.which == 2) return; - - var elm = jqLite(event.target); - - // traverse the DOM up to find first A tag - while (lowercase(elm[0].nodeName) !== 'a') { - // ignore rewriting if no A tag (reached root element, or no parent - removed from document) - if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return; - } - - var absHref = elm.prop('href'); - // get the actual href attribute - see - // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx - var relHref = elm.attr('href') || elm.attr('xlink:href'); - - if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') { - // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during - // an animation. - absHref = urlResolve(absHref.animVal).href; - } - - // Ignore when url is started with javascript: or mailto: - if (IGNORE_URI_REGEXP.test(absHref)) return; - - if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { - if ($location.$$parseLinkUrl(absHref, relHref)) { - // We do a preventDefault for all urls that are part of the angular application, - // in html5mode and also without, so that we are able to abort navigation without - // getting double entries in the location history. - event.preventDefault(); - // update location manually - if ($location.absUrl() != $browser.url()) { - $rootScope.$apply(); - // hack to work around FF6 bug 684208 when scenario runner clicks on links - window.angular['ff-684208-preventDefault'] = true; - } - } - } - }); - - - // rewrite hashbang url <> html5 url - if ($location.absUrl() != initialUrl) { - $browser.url($location.absUrl(), true); - } - - // update $location when $browser url changes - $browser.onUrlChange(function(newUrl) { - if ($location.absUrl() != newUrl) { - $rootScope.$evalAsync(function() { - var oldUrl = $location.absUrl(); - - $location.$$parse(newUrl); - if ($rootScope.$broadcast('$locationChangeStart', newUrl, - oldUrl).defaultPrevented) { - $location.$$parse(oldUrl); - $browser.url(oldUrl); - } else { - afterLocationChange(oldUrl); - } - }); - if (!$rootScope.$$phase) $rootScope.$digest(); - } - }); - - // update browser - var changeCounter = 0; - $rootScope.$watch(function $locationWatch() { - var oldUrl = $browser.url(); - var currentReplace = $location.$$replace; - - if (!changeCounter || oldUrl != $location.absUrl()) { - changeCounter++; - $rootScope.$evalAsync(function() { - if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl). - defaultPrevented) { - $location.$$parse(oldUrl); - } else { - $browser.url($location.absUrl(), currentReplace); - afterLocationChange(oldUrl); - } - }); - } - $location.$$replace = false; - - return changeCounter; - }); - - return $location; - - function afterLocationChange(oldUrl) { - $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl); - } -}]; -} - -/** - * @ngdoc service - * @name $log - * @requires $window - * - * @description - * Simple service for logging. Default implementation safely writes the message - * into the browser's console (if present). - * - * The main purpose of this service is to simplify debugging and troubleshooting. - * - * The default is to log `debug` messages. You can use - * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. - * - * @example - - - angular.module('logExample', []) - .controller('LogController', ['$scope', '$log', function($scope, $log) { - $scope.$log = $log; - $scope.message = 'Hello World!'; - }]); - - -
-

Reload this page with open console, enter text and hit the log button...

- Message: - - - - - -
-
-
- */ - -/** - * @ngdoc provider - * @name $logProvider - * @description - * Use the `$logProvider` to configure how the application logs messages - */ -function $LogProvider(){ - var debug = true, - self = this; - - /** - * @ngdoc method - * @name $logProvider#debugEnabled - * @description - * @param {boolean=} flag enable or disable debug level messages - * @returns {*} current value if used as getter or itself (chaining) if used as setter - */ - this.debugEnabled = function(flag) { - if (isDefined(flag)) { - debug = flag; - return this; - } else { - return debug; - } - }; - - this.$get = ['$window', function($window){ - return { - /** - * @ngdoc method - * @name $log#log - * - * @description - * Write a log message - */ - log: consoleLog('log'), - - /** - * @ngdoc method - * @name $log#info - * - * @description - * Write an information message - */ - info: consoleLog('info'), - - /** - * @ngdoc method - * @name $log#warn - * - * @description - * Write a warning message - */ - warn: consoleLog('warn'), - - /** - * @ngdoc method - * @name $log#error - * - * @description - * Write an error message - */ - error: consoleLog('error'), - - /** - * @ngdoc method - * @name $log#debug - * - * @description - * Write a debug message - */ - debug: (function () { - var fn = consoleLog('debug'); - - return function() { - if (debug) { - fn.apply(self, arguments); - } - }; - }()) - }; - - function formatError(arg) { - if (arg instanceof Error) { - if (arg.stack) { - arg = (arg.message && arg.stack.indexOf(arg.message) === -1) - ? 'Error: ' + arg.message + '\n' + arg.stack - : arg.stack; - } else if (arg.sourceURL) { - arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line; - } - } - return arg; - } - - function consoleLog(type) { - var console = $window.console || {}, - logFn = console[type] || console.log || noop, - hasApply = false; - - // Note: reading logFn.apply throws an error in IE11 in IE8 document mode. - // The reason behind this is that console.log has type "object" in IE8... - try { - hasApply = !!logFn.apply; - } catch (e) {} - - if (hasApply) { - return function() { - var args = []; - forEach(arguments, function(arg) { - args.push(formatError(arg)); - }); - return logFn.apply(console, args); - }; - } - - // we are IE which either doesn't have window.console => this is noop and we do nothing, - // or we are IE where console.log doesn't have apply so we log at least first 2 args - return function(arg1, arg2) { - logFn(arg1, arg2 == null ? '' : arg2); - }; - } - }]; -} - -var $parseMinErr = minErr('$parse'); -var promiseWarningCache = {}; -var promiseWarning; - -// Sandboxing Angular Expressions -// ------------------------------ -// Angular expressions are generally considered safe because these expressions only have direct -// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by -// obtaining a reference to native JS functions such as the Function constructor. -// -// As an example, consider the following Angular expression: -// -// {}.toString.constructor('alert("evil JS code")') -// -// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits -// against the expression language, but not to prevent exploits that were enabled by exposing -// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good -// practice and therefore we are not even trying to protect against interaction with an object -// explicitly exposed in this way. -// -// In general, it is not possible to access a Window object from an angular expression unless a -// window or some DOM object that has a reference to window is published onto a Scope. -// Similarly we prevent invocations of function known to be dangerous, as well as assignments to -// native objects. -// -// See https://docs.angularjs.org/guide/security - - -function ensureSafeMemberName(name, fullExpression) { - if (name === "__defineGetter__" || name === "__defineSetter__" - || name === "__lookupGetter__" || name === "__lookupSetter__" - || name === "__proto__") { - throw $parseMinErr('isecfld', - 'Attempting to access a disallowed field in Angular expressions! ' - +'Expression: {0}', fullExpression); - } - return name; -} - -function ensureSafeObject(obj, fullExpression) { - // nifty check if obj is Function that is fast and works across iframes and other contexts - if (obj) { - if (obj.constructor === obj) { - throw $parseMinErr('isecfn', - 'Referencing Function in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (// isWindow(obj) - obj.document && obj.location && obj.alert && obj.setInterval) { - throw $parseMinErr('isecwindow', - 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (// isElement(obj) - obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) { - throw $parseMinErr('isecdom', - 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (// block Object so that we can't get hold of dangerous Object.* methods - obj === Object) { - throw $parseMinErr('isecobj', - 'Referencing Object in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } - } - return obj; -} - -var CALL = Function.prototype.call; -var APPLY = Function.prototype.apply; -var BIND = Function.prototype.bind; - -function ensureSafeFunction(obj, fullExpression) { - if (obj) { - if (obj.constructor === obj) { - throw $parseMinErr('isecfn', - 'Referencing Function in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) { - throw $parseMinErr('isecff', - 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}', - fullExpression); - } - } -} - -var OPERATORS = { - /* jshint bitwise : false */ - 'null':function(){return null;}, - 'true':function(){return true;}, - 'false':function(){return false;}, - undefined:noop, - '+':function(self, locals, a,b){ - a=a(self, locals); b=b(self, locals); - if (isDefined(a)) { - if (isDefined(b)) { - return a + b; - } - return a; - } - return isDefined(b)?b:undefined;}, - '-':function(self, locals, a,b){ - a=a(self, locals); b=b(self, locals); - return (isDefined(a)?a:0)-(isDefined(b)?b:0); - }, - '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);}, - '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);}, - '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);}, - '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);}, - '=':noop, - '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);}, - '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);}, - '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);}, - '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);}, - '<':function(self, locals, a,b){return a(self, locals)':function(self, locals, a,b){return a(self, locals)>b(self, locals);}, - '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);}, - '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);}, - '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);}, - '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);}, - '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);}, -// '|':function(self, locals, a,b){return a|b;}, - '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));}, - '!':function(self, locals, a){return !a(self, locals);} -}; -/* jshint bitwise: true */ -var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; - - -///////////////////////////////////////// - - -/** - * @constructor - */ -var Lexer = function (options) { - this.options = options; -}; - -Lexer.prototype = { - constructor: Lexer, - - lex: function (text) { - this.text = text; - - this.index = 0; - this.ch = undefined; - this.lastCh = ':'; // can start regexp - - this.tokens = []; - - while (this.index < this.text.length) { - this.ch = this.text.charAt(this.index); - if (this.is('"\'')) { - this.readString(this.ch); - } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) { - this.readNumber(); - } else if (this.isIdent(this.ch)) { - this.readIdent(); - } else if (this.is('(){}[].,;:?')) { - this.tokens.push({ - index: this.index, - text: this.ch - }); - this.index++; - } else if (this.isWhitespace(this.ch)) { - this.index++; - continue; - } else { - var ch2 = this.ch + this.peek(); - var ch3 = ch2 + this.peek(2); - var fn = OPERATORS[this.ch]; - var fn2 = OPERATORS[ch2]; - var fn3 = OPERATORS[ch3]; - if (fn3) { - this.tokens.push({index: this.index, text: ch3, fn: fn3}); - this.index += 3; - } else if (fn2) { - this.tokens.push({index: this.index, text: ch2, fn: fn2}); - this.index += 2; - } else if (fn) { - this.tokens.push({ - index: this.index, - text: this.ch, - fn: fn - }); - this.index += 1; - } else { - this.throwError('Unexpected next character ', this.index, this.index + 1); - } - } - this.lastCh = this.ch; - } - return this.tokens; - }, - - is: function(chars) { - return chars.indexOf(this.ch) !== -1; - }, - - was: function(chars) { - return chars.indexOf(this.lastCh) !== -1; - }, - - peek: function(i) { - var num = i || 1; - return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false; - }, - - isNumber: function(ch) { - return ('0' <= ch && ch <= '9'); - }, - - isWhitespace: function(ch) { - // IE treats non-breaking space as \u00A0 - return (ch === ' ' || ch === '\r' || ch === '\t' || - ch === '\n' || ch === '\v' || ch === '\u00A0'); - }, - - isIdent: function(ch) { - return ('a' <= ch && ch <= 'z' || - 'A' <= ch && ch <= 'Z' || - '_' === ch || ch === '$'); - }, - - isExpOperator: function(ch) { - return (ch === '-' || ch === '+' || this.isNumber(ch)); - }, - - throwError: function(error, start, end) { - end = end || this.index; - var colStr = (isDefined(start) - ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']' - : ' ' + end); - throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].', - error, colStr, this.text); - }, - - readNumber: function() { - var number = ''; - var start = this.index; - while (this.index < this.text.length) { - var ch = lowercase(this.text.charAt(this.index)); - if (ch == '.' || this.isNumber(ch)) { - number += ch; - } else { - var peekCh = this.peek(); - if (ch == 'e' && this.isExpOperator(peekCh)) { - number += ch; - } else if (this.isExpOperator(ch) && - peekCh && this.isNumber(peekCh) && - number.charAt(number.length - 1) == 'e') { - number += ch; - } else if (this.isExpOperator(ch) && - (!peekCh || !this.isNumber(peekCh)) && - number.charAt(number.length - 1) == 'e') { - this.throwError('Invalid exponent'); - } else { - break; - } - } - this.index++; - } - number = 1 * number; - this.tokens.push({ - index: start, - text: number, - literal: true, - constant: true, - fn: function() { return number; } - }); - }, - - readIdent: function() { - var parser = this; - - var ident = ''; - var start = this.index; - - var lastDot, peekIndex, methodName, ch; - - while (this.index < this.text.length) { - ch = this.text.charAt(this.index); - if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) { - if (ch === '.') lastDot = this.index; - ident += ch; - } else { - break; - } - this.index++; - } - - //check if this is not a method invocation and if it is back out to last dot - if (lastDot) { - peekIndex = this.index; - while (peekIndex < this.text.length) { - ch = this.text.charAt(peekIndex); - if (ch === '(') { - methodName = ident.substr(lastDot - start + 1); - ident = ident.substr(0, lastDot - start); - this.index = peekIndex; - break; - } - if (this.isWhitespace(ch)) { - peekIndex++; - } else { - break; - } - } - } - - - var token = { - index: start, - text: ident - }; - - // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn - if (OPERATORS.hasOwnProperty(ident)) { - token.fn = OPERATORS[ident]; - token.literal = true; - token.constant = true; - } else { - var getter = getterFn(ident, this.options, this.text); - token.fn = extend(function(self, locals) { - return (getter(self, locals)); - }, { - assign: function(self, value) { - return setter(self, ident, value, parser.text, parser.options); - } - }); - } - - this.tokens.push(token); - - if (methodName) { - this.tokens.push({ - index:lastDot, - text: '.' - }); - this.tokens.push({ - index: lastDot + 1, - text: methodName - }); - } - }, - - readString: function(quote) { - var start = this.index; - this.index++; - var string = ''; - var rawString = quote; - var escape = false; - while (this.index < this.text.length) { - var ch = this.text.charAt(this.index); - rawString += ch; - if (escape) { - if (ch === 'u') { - var hex = this.text.substring(this.index + 1, this.index + 5); - if (!hex.match(/[\da-f]{4}/i)) - this.throwError('Invalid unicode escape [\\u' + hex + ']'); - this.index += 4; - string += String.fromCharCode(parseInt(hex, 16)); - } else { - var rep = ESCAPE[ch]; - string = string + (rep || ch); - } - escape = false; - } else if (ch === '\\') { - escape = true; - } else if (ch === quote) { - this.index++; - this.tokens.push({ - index: start, - text: rawString, - string: string, - literal: true, - constant: true, - fn: function() { return string; } - }); - return; - } else { - string += ch; - } - this.index++; - } - this.throwError('Unterminated quote', start); - } -}; - - -/** - * @constructor - */ -var Parser = function (lexer, $filter, options) { - this.lexer = lexer; - this.$filter = $filter; - this.options = options; -}; - -Parser.ZERO = extend(function () { - return 0; -}, { - constant: true -}); - -Parser.prototype = { - constructor: Parser, - - parse: function (text) { - this.text = text; - - this.tokens = this.lexer.lex(text); - - var value = this.statements(); - - if (this.tokens.length !== 0) { - this.throwError('is an unexpected token', this.tokens[0]); - } - - value.literal = !!value.literal; - value.constant = !!value.constant; - - return value; - }, - - primary: function () { - var primary; - if (this.expect('(')) { - primary = this.filterChain(); - this.consume(')'); - } else if (this.expect('[')) { - primary = this.arrayDeclaration(); - } else if (this.expect('{')) { - primary = this.object(); - } else { - var token = this.expect(); - primary = token.fn; - if (!primary) { - this.throwError('not a primary expression', token); - } - primary.literal = !!token.literal; - primary.constant = !!token.constant; - } - - var next, context; - while ((next = this.expect('(', '[', '.'))) { - if (next.text === '(') { - primary = this.functionCall(primary, context); - context = null; - } else if (next.text === '[') { - context = primary; - primary = this.objectIndex(primary); - } else if (next.text === '.') { - context = primary; - primary = this.fieldAccess(primary); - } else { - this.throwError('IMPOSSIBLE'); - } - } - return primary; - }, - - throwError: function(msg, token) { - throw $parseMinErr('syntax', - 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].', - token.text, msg, (token.index + 1), this.text, this.text.substring(token.index)); - }, - - peekToken: function() { - if (this.tokens.length === 0) - throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); - return this.tokens[0]; - }, - - peek: function(e1, e2, e3, e4) { - if (this.tokens.length > 0) { - var token = this.tokens[0]; - var t = token.text; - if (t === e1 || t === e2 || t === e3 || t === e4 || - (!e1 && !e2 && !e3 && !e4)) { - return token; - } - } - return false; - }, - - expect: function(e1, e2, e3, e4){ - var token = this.peek(e1, e2, e3, e4); - if (token) { - this.tokens.shift(); - return token; - } - return false; - }, - - consume: function(e1){ - if (!this.expect(e1)) { - this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); - } - }, - - unaryFn: function(fn, right) { - return extend(function(self, locals) { - return fn(self, locals, right); - }, { - constant:right.constant - }); - }, - - ternaryFn: function(left, middle, right){ - return extend(function(self, locals){ - return left(self, locals) ? middle(self, locals) : right(self, locals); - }, { - constant: left.constant && middle.constant && right.constant - }); - }, - - binaryFn: function(left, fn, right) { - return extend(function(self, locals) { - return fn(self, locals, left, right); - }, { - constant:left.constant && right.constant - }); - }, - - statements: function() { - var statements = []; - while (true) { - if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']')) - statements.push(this.filterChain()); - if (!this.expect(';')) { - // optimize for the common case where there is only one statement. - // TODO(size): maybe we should not support multiple statements? - return (statements.length === 1) - ? statements[0] - : function(self, locals) { - var value; - for (var i = 0; i < statements.length; i++) { - var statement = statements[i]; - if (statement) { - value = statement(self, locals); - } - } - return value; - }; - } - } - }, - - filterChain: function() { - var left = this.expression(); - var token; - while (true) { - if ((token = this.expect('|'))) { - left = this.binaryFn(left, token.fn, this.filter()); - } else { - return left; - } - } - }, - - filter: function() { - var token = this.expect(); - var fn = this.$filter(token.text); - var argsFn = []; - while (true) { - if ((token = this.expect(':'))) { - argsFn.push(this.expression()); - } else { - var fnInvoke = function(self, locals, input) { - var args = [input]; - for (var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self, locals)); - } - return fn.apply(self, args); - }; - return function() { - return fnInvoke; - }; - } - } - }, - - expression: function() { - return this.assignment(); - }, - - assignment: function() { - var left = this.ternary(); - var right; - var token; - if ((token = this.expect('='))) { - if (!left.assign) { - this.throwError('implies assignment but [' + - this.text.substring(0, token.index) + '] can not be assigned to', token); - } - right = this.ternary(); - return function(scope, locals) { - return left.assign(scope, right(scope, locals), locals); - }; - } - return left; - }, - - ternary: function() { - var left = this.logicalOR(); - var middle; - var token; - if ((token = this.expect('?'))) { - middle = this.assignment(); - if ((token = this.expect(':'))) { - return this.ternaryFn(left, middle, this.assignment()); - } else { - this.throwError('expected :', token); - } - } else { - return left; - } - }, - - logicalOR: function() { - var left = this.logicalAND(); - var token; - while (true) { - if ((token = this.expect('||'))) { - left = this.binaryFn(left, token.fn, this.logicalAND()); - } else { - return left; - } - } - }, - - logicalAND: function() { - var left = this.equality(); - var token; - if ((token = this.expect('&&'))) { - left = this.binaryFn(left, token.fn, this.logicalAND()); - } - return left; - }, - - equality: function() { - var left = this.relational(); - var token; - if ((token = this.expect('==','!=','===','!=='))) { - left = this.binaryFn(left, token.fn, this.equality()); - } - return left; - }, - - relational: function() { - var left = this.additive(); - var token; - if ((token = this.expect('<', '>', '<=', '>='))) { - left = this.binaryFn(left, token.fn, this.relational()); - } - return left; - }, - - additive: function() { - var left = this.multiplicative(); - var token; - while ((token = this.expect('+','-'))) { - left = this.binaryFn(left, token.fn, this.multiplicative()); - } - return left; - }, - - multiplicative: function() { - var left = this.unary(); - var token; - while ((token = this.expect('*','/','%'))) { - left = this.binaryFn(left, token.fn, this.unary()); - } - return left; - }, - - unary: function() { - var token; - if (this.expect('+')) { - return this.primary(); - } else if ((token = this.expect('-'))) { - return this.binaryFn(Parser.ZERO, token.fn, this.unary()); - } else if ((token = this.expect('!'))) { - return this.unaryFn(token.fn, this.unary()); - } else { - return this.primary(); - } - }, - - fieldAccess: function(object) { - var parser = this; - var field = this.expect().text; - var getter = getterFn(field, this.options, this.text); - - return extend(function(scope, locals, self) { - return getter(self || object(scope, locals)); - }, { - assign: function(scope, value, locals) { - var o = object(scope, locals); - if (!o) object.assign(scope, o = {}); - return setter(o, field, value, parser.text, parser.options); - } - }); - }, - - objectIndex: function(obj) { - var parser = this; - - var indexFn = this.expression(); - this.consume(']'); - - return extend(function(self, locals) { - var o = obj(self, locals), - i = indexFn(self, locals), - v, p; - - ensureSafeMemberName(i, parser.text); - if (!o) return undefined; - v = ensureSafeObject(o[i], parser.text); - if (v && v.then && parser.options.unwrapPromises) { - p = v; - if (!('$$v' in v)) { - p.$$v = undefined; - p.then(function(val) { p.$$v = val; }); - } - v = v.$$v; - } - return v; - }, { - assign: function(self, value, locals) { - var key = ensureSafeMemberName(indexFn(self, locals), parser.text); - // prevent overwriting of Function.constructor which would break ensureSafeObject check - var o = ensureSafeObject(obj(self, locals), parser.text); - if (!o) obj.assign(self, o = {}); - return o[key] = value; - } - }); - }, - - functionCall: function(fn, contextGetter) { - var argsFn = []; - if (this.peekToken().text !== ')') { - do { - argsFn.push(this.expression()); - } while (this.expect(',')); - } - this.consume(')'); - - var parser = this; - - return function(scope, locals) { - var args = []; - var context = contextGetter ? contextGetter(scope, locals) : scope; - - for (var i = 0; i < argsFn.length; i++) { - args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text)); - } - var fnPtr = fn(scope, locals, context) || noop; - - ensureSafeObject(context, parser.text); - ensureSafeFunction(fnPtr, parser.text); - - // IE doesn't have apply for some native functions - var v = fnPtr.apply - ? fnPtr.apply(context, args) - : fnPtr(args[0], args[1], args[2], args[3], args[4]); - - return ensureSafeObject(v, parser.text); - }; - }, - - // This is used with json array declaration - arrayDeclaration: function () { - var elementFns = []; - var allConstant = true; - if (this.peekToken().text !== ']') { - do { - if (this.peek(']')) { - // Support trailing commas per ES5.1. - break; - } - var elementFn = this.expression(); - elementFns.push(elementFn); - if (!elementFn.constant) { - allConstant = false; - } - } while (this.expect(',')); - } - this.consume(']'); - - return extend(function(self, locals) { - var array = []; - for (var i = 0; i < elementFns.length; i++) { - array.push(elementFns[i](self, locals)); - } - return array; - }, { - literal: true, - constant: allConstant - }); - }, - - object: function () { - var keyValues = []; - var allConstant = true; - if (this.peekToken().text !== '}') { - do { - if (this.peek('}')) { - // Support trailing commas per ES5.1. - break; - } - var token = this.expect(), - key = token.string || token.text; - this.consume(':'); - var value = this.expression(); - keyValues.push({key: key, value: value}); - if (!value.constant) { - allConstant = false; - } - } while (this.expect(',')); - } - this.consume('}'); - - return extend(function(self, locals) { - var object = {}; - for (var i = 0; i < keyValues.length; i++) { - var keyValue = keyValues[i]; - object[keyValue.key] = keyValue.value(self, locals); - } - return object; - }, { - literal: true, - constant: allConstant - }); - } -}; - - -////////////////////////////////////////////////// -// Parser helper functions -////////////////////////////////////////////////// - -function setter(obj, path, setValue, fullExp, options) { - ensureSafeObject(obj, fullExp); - - //needed? - options = options || {}; - - var element = path.split('.'), key; - for (var i = 0; element.length > 1; i++) { - key = ensureSafeMemberName(element.shift(), fullExp); - var propertyObj = ensureSafeObject(obj[key], fullExp); - if (!propertyObj) { - propertyObj = {}; - obj[key] = propertyObj; - } - obj = propertyObj; - if (obj.then && options.unwrapPromises) { - promiseWarning(fullExp); - if (!("$$v" in obj)) { - (function(promise) { - promise.then(function(val) { promise.$$v = val; }); } - )(obj); - } - if (obj.$$v === undefined) { - obj.$$v = {}; - } - obj = obj.$$v; - } - } - key = ensureSafeMemberName(element.shift(), fullExp); - ensureSafeObject(obj[key], fullExp); - obj[key] = setValue; - return setValue; -} - -var getterFnCacheDefault = {}; -var getterFnCacheExpensive = {}; - -function isPossiblyDangerousMemberName(name) { - return name == 'constructor'; -} - -/** - * Implementation of the "Black Hole" variant from: - * - http://jsperf.com/angularjs-parse-getter/4 - * - http://jsperf.com/path-evaluation-simplified/7 - */ -function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) { - ensureSafeMemberName(key0, fullExp); - ensureSafeMemberName(key1, fullExp); - ensureSafeMemberName(key2, fullExp); - ensureSafeMemberName(key3, fullExp); - ensureSafeMemberName(key4, fullExp); - var eso = function(o) { - return ensureSafeObject(o, fullExp); - }; - var expensiveChecks = options.expensiveChecks; - var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity; - var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity; - var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity; - var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity; - var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity; - - return !options.unwrapPromises - ? function cspSafeGetter(scope, locals) { - var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope; - - if (pathVal == null) return pathVal; - pathVal = eso0(pathVal[key0]); - - if (!key1) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso1(pathVal[key1]); - - if (!key2) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso2(pathVal[key2]); - - if (!key3) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso3(pathVal[key3]); - - if (!key4) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso4(pathVal[key4]); - - return pathVal; - } - : function cspSafePromiseEnabledGetter(scope, locals) { - var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope, - promise; - - if (pathVal == null) return pathVal; - - pathVal = eso0(pathVal[key0]); - if (pathVal && pathVal.then) { - promiseWarning(fullExp); - if (!("$$v" in pathVal)) { - promise = pathVal; - promise.$$v = undefined; - promise.then(function(val) { promise.$$v = eso0(val); }); - } - pathVal = eso0(pathVal.$$v); - } - - if (!key1) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso1(pathVal[key1]); - if (pathVal && pathVal.then) { - promiseWarning(fullExp); - if (!("$$v" in pathVal)) { - promise = pathVal; - promise.$$v = undefined; - promise.then(function(val) { promise.$$v = eso1(val); }); - } - pathVal = eso1(pathVal.$$v); - } - - if (!key2) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso2(pathVal[key2]); - if (pathVal && pathVal.then) { - promiseWarning(fullExp); - if (!("$$v" in pathVal)) { - promise = pathVal; - promise.$$v = undefined; - promise.then(function(val) { promise.$$v = eso2(val); }); - } - pathVal = eso2(pathVal.$$v); - } - - if (!key3) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso3(pathVal[key3]); - if (pathVal && pathVal.then) { - promiseWarning(fullExp); - if (!("$$v" in pathVal)) { - promise = pathVal; - promise.$$v = undefined; - promise.then(function(val) { promise.$$v = eso3(val); }); - } - pathVal = eso3(pathVal.$$v); - } - - if (!key4) return pathVal; - if (pathVal == null) return undefined; - pathVal = eso4(pathVal[key4]); - if (pathVal && pathVal.then) { - promiseWarning(fullExp); - if (!("$$v" in pathVal)) { - promise = pathVal; - promise.$$v = undefined; - promise.then(function(val) { promise.$$v = eso4(val); }); - } - pathVal = eso4(pathVal.$$v); - } - return pathVal; - }; -} - -function getterFnWithExtraArgs(fn, fullExpression) { - return function(s, l) { - return fn(s, l, promiseWarning, ensureSafeObject, fullExpression); - }; -} - -function getterFn(path, options, fullExp) { - var expensiveChecks = options.expensiveChecks; - var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault); - // Check whether the cache has this getter already. - // We can use hasOwnProperty directly on the cache because we ensure, - // see below, that the cache never stores a path called 'hasOwnProperty' - if (getterFnCache.hasOwnProperty(path)) { - return getterFnCache[path]; - } - - var pathKeys = path.split('.'), - pathKeysLength = pathKeys.length, - fn; - - // http://jsperf.com/angularjs-parse-getter/6 - if (options.csp) { - if (pathKeysLength < 6) { - fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, - options); - } else { - fn = function(scope, locals) { - var i = 0, val; - do { - val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], - pathKeys[i++], fullExp, options)(scope, locals); - - locals = undefined; // clear after first iteration - scope = val; - } while (i < pathKeysLength); - return val; - }; - } - } else { - var code = 'var p;\n'; - if (expensiveChecks) { - code += 's = eso(s, fe);\nl = eso(l, fe);\n'; - } - var needsEnsureSafeObject = expensiveChecks; - forEach(pathKeys, function(key, index) { - ensureSafeMemberName(key, fullExp); - var lookupJs = (index - // we simply dereference 's' on any .dot notation - ? 's' - // but if we are first then we check locals first, and if so read it first - : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '["' + key + '"]'; - var wrapWithEso = expensiveChecks || isPossiblyDangerousMemberName(key); - if (wrapWithEso) { - lookupJs = 'eso(' + lookupJs + ', fe)'; - needsEnsureSafeObject = true; - } - code += 'if(s == null) return undefined;\n' + - 's=' + lookupJs + ';\n'; - if (options.unwrapPromises) { - code += 'if (s && s.then) {\n' + - ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' + - ' if (!("$$v" in s)) {\n' + - ' p=s;\n' + - ' p.$$v = undefined;\n' + - ' p.then(function(v) {p.$$v=' + (wrapWithEso ? 'eso(v)' : 'v') + ';});\n' + - '}\n' + - ' s=' + (wrapWithEso ? 'eso(s.$$v)' : 's.$$v') + '\n' + - '}\n'; - - } - }); - code += 'return s;'; - - /* jshint -W054 */ - // s=scope, l=locals, pw=promiseWarning, eso=ensureSafeObject, fe=fullExpression - var evaledFnGetter = new Function('s', 'l', 'pw', 'eso', 'fe', code); - /* jshint +W054 */ - evaledFnGetter.toString = valueFn(code); - if (needsEnsureSafeObject || options.unwrapPromises) { - evaledFnGetter = getterFnWithExtraArgs(evaledFnGetter, fullExp); - } - fn = evaledFnGetter; - } - - // Only cache the value if it's not going to mess up the cache object - // This is more performant that using Object.prototype.hasOwnProperty.call - if (path !== 'hasOwnProperty') { - getterFnCache[path] = fn; - } - return fn; -} - -/////////////////////////////////// - -/** - * @ngdoc service - * @name $parse - * @kind function - * - * @description - * - * Converts Angular {@link guide/expression expression} into a function. - * - * ```js - * var getter = $parse('user.name'); - * var setter = getter.assign; - * var context = {user:{name:'angular'}}; - * var locals = {user:{name:'local'}}; - * - * expect(getter(context)).toEqual('angular'); - * setter(context, 'newValue'); - * expect(context.user.name).toEqual('newValue'); - * expect(getter(context, locals)).toEqual('local'); - * ``` - * - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - * - * The returned function also has the following properties: - * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript - * literal. - * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript - * constant literals. - * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be - * set to a function to change its value on the given context. - * - */ - - -/** - * @ngdoc provider - * @name $parseProvider - * @kind function - * - * @description - * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} - * service. - */ -function $ParseProvider() { - var cacheDefault = {}; - var cacheExpensive = {}; - - var $parseOptions = { - csp: false, - unwrapPromises: false, - logPromiseWarnings: true, - expensiveChecks: false - }; - - - /** - * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. - * - * @ngdoc method - * @name $parseProvider#unwrapPromises - * @description - * - * **This feature is deprecated, see deprecation notes below for more info** - * - * If set to true (default is false), $parse will unwrap promises automatically when a promise is - * found at any part of the expression. In other words, if set to true, the expression will always - * result in a non-promise value. - * - * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled, - * the fulfillment value is used in place of the promise while evaluating the expression. - * - * **Deprecation notice** - * - * This is a feature that didn't prove to be wildly useful or popular, primarily because of the - * dichotomy between data access in templates (accessed as raw values) and controller code - * (accessed as promises). - * - * In most code we ended up resolving promises manually in controllers anyway and thus unifying - * the model access there. - * - * Other downsides of automatic promise unwrapping: - * - * - when building components it's often desirable to receive the raw promises - * - adds complexity and slows down expression evaluation - * - makes expression code pre-generation unattractive due to the amount of code that needs to be - * generated - * - makes IDE auto-completion and tool support hard - * - * **Warning Logs** - * - * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a - * promise (to reduce the noise, each expression is logged only once). To disable this logging use - * `$parseProvider.logPromiseWarnings(false)` api. - * - * - * @param {boolean=} value New value. - * @returns {boolean|self} Returns the current setting when used as getter and self if used as - * setter. - */ - this.unwrapPromises = function(value) { - if (isDefined(value)) { - $parseOptions.unwrapPromises = !!value; - return this; - } else { - return $parseOptions.unwrapPromises; - } - }; - - - /** - * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future. - * - * @ngdoc method - * @name $parseProvider#logPromiseWarnings - * @description - * - * Controls whether Angular should log a warning on any encounter of a promise in an expression. - * - * The default is set to `true`. - * - * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well. - * - * @param {boolean=} value New value. - * @returns {boolean|self} Returns the current setting when used as getter and self if used as - * setter. - */ - this.logPromiseWarnings = function(value) { - if (isDefined(value)) { - $parseOptions.logPromiseWarnings = value; - return this; - } else { - return $parseOptions.logPromiseWarnings; - } - }; - - - this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) { - $parseOptions.csp = $sniffer.csp; - var $parseOptionsExpensive = { - csp: $parseOptions.csp, - unwrapPromises: $parseOptions.unwrapPromises, - logPromiseWarnings: $parseOptions.logPromiseWarnings, - expensiveChecks: true - }; - - promiseWarning = function promiseWarningFn(fullExp) { - if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return; - promiseWarningCache[fullExp] = true; - $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' + - 'Automatic unwrapping of promises in Angular expressions is deprecated.'); - }; - - return function(exp, expensiveChecks) { - var parsedExpression; - - switch (typeof exp) { - case 'string': - - var cache = (expensiveChecks ? cacheExpensive : cacheDefault); - if (cache.hasOwnProperty(exp)) { - return cache[exp]; - } - - var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions; - var lexer = new Lexer(parseOptions); - var parser = new Parser(lexer, $filter, parseOptions); - parsedExpression = parser.parse(exp); - - if (exp !== 'hasOwnProperty') { - // Only cache the value if it's not going to mess up the cache object - // This is more performant that using Object.prototype.hasOwnProperty.call - cache[exp] = parsedExpression; - } - - return parsedExpression; - - case 'function': - return exp; - - default: - return noop; - } - }; - }]; -} - -/** - * @ngdoc service - * @name $q - * @requires $rootScope - * - * @description - * A service that helps you run functions asynchronously, and use their return values (or exceptions) - * when they are done processing. - * - * This is an implementation of promises/deferred objects inspired by - * [Kris Kowal's Q](https://github.com/kriskowal/q). - * - * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an - * interface for interacting with an object that represents the result of an action that is - * performed asynchronously, and may or may not be finished at any given point in time. - * - * From the perspective of dealing with error handling, deferred and promise APIs are to - * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. - * - * ```js - * // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet` - * // are available in the current lexical scope (they could have been injected or passed in). - * - * function asyncGreet(name) { - * var deferred = $q.defer(); - * - * setTimeout(function() { - * deferred.notify('About to greet ' + name + '.'); - * - * if (okToGreet(name)) { - * deferred.resolve('Hello, ' + name + '!'); - * } else { - * deferred.reject('Greeting ' + name + ' is not allowed.'); - * } - * }, 1000); - * - * return deferred.promise; - * } - * - * var promise = asyncGreet('Robin Hood'); - * promise.then(function(greeting) { - * alert('Success: ' + greeting); - * }, function(reason) { - * alert('Failed: ' + reason); - * }, function(update) { - * alert('Got notification: ' + update); - * }); - * ``` - * - * At first it might not be obvious why this extra complexity is worth the trouble. The payoff - * comes in the way of guarantees that promise and deferred APIs make, see - * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md. - * - * Additionally the promise api allows for composition that is very hard to do with the - * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. - * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the - * section on serial or parallel joining of promises. - * - * - * # The Deferred API - * - * A new instance of deferred is constructed by calling `$q.defer()`. - * - * The purpose of the deferred object is to expose the associated Promise instance as well as APIs - * that can be used for signaling the successful or unsuccessful completion, as well as the status - * of the task. - * - * **Methods** - * - * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection - * constructed via `$q.reject`, the promise will be rejected instead. - * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to - * resolving it with a rejection constructed via `$q.reject`. - * - `notify(value)` - provides updates on the status of the promise's execution. This may be called - * multiple times before the promise is either resolved or rejected. - * - * **Properties** - * - * - promise – `{Promise}` – promise object associated with this deferred. - * - * - * # The Promise API - * - * A new promise instance is created when a deferred instance is created and can be retrieved by - * calling `deferred.promise`. - * - * The purpose of the promise object is to allow for interested parties to get access to the result - * of the deferred task when it completes. - * - * **Methods** - * - * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or - * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously - * as soon as the result is available. The callbacks are called with a single argument: the result - * or rejection reason. Additionally, the notify callback may be called zero or more times to - * provide a progress indication, before the promise is resolved or rejected. - * - * This method *returns a new promise* which is resolved or rejected via the return value of the - * `successCallback`, `errorCallback`. It also notifies via the return value of the - * `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback - * method. - * - * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` - * - * Because `catch` is a reserved word in JavaScript and reserved keywords are not supported as - * property names by ES3, you'll need to invoke the method like `promise['catch'](callback)` or - * `promise.then(null, errorCallback)` to make your code IE8 and Android 2.x compatible. - * - * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise, - * but to do so without modifying the final value. This is useful to release resources or do some - * clean-up that needs to be done whether the promise was rejected or resolved. See the [full - * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for - * more information. - * - * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as - * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to - * make your code IE8 and Android 2.x compatible. - * - * # Chaining promises - * - * Because calling the `then` method of a promise returns a new derived promise, it is easily - * possible to create a chain of promises: - * - * ```js - * promiseB = promiseA.then(function(result) { - * return result + 1; - * }); - * - * // promiseB will be resolved immediately after promiseA is resolved and its value - * // will be the result of promiseA incremented by 1 - * ``` - * - * It is possible to create chains of any length and since a promise can be resolved with another - * promise (which will defer its resolution further), it is possible to pause/defer resolution of - * the promises at any point in the chain. This makes it possible to implement powerful APIs like - * $http's response interceptors. - * - * - * # Differences between Kris Kowal's Q and $q - * - * There are two main differences: - * - * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation - * mechanism in angular, which means faster propagation of resolution or rejection into your - * models and avoiding unnecessary browser repaints, which would result in flickering UI. - * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains - * all the important functionality needed for common async tasks. - * - * # Testing - * - * ```js - * it('should simulate promise', inject(function($q, $rootScope) { - * var deferred = $q.defer(); - * var promise = deferred.promise; - * var resolvedValue; - * - * promise.then(function(value) { resolvedValue = value; }); - * expect(resolvedValue).toBeUndefined(); - * - * // Simulate resolving of promise - * deferred.resolve(123); - * // Note that the 'then' function does not get called synchronously. - * // This is because we want the promise API to always be async, whether or not - * // it got called synchronously or asynchronously. - * expect(resolvedValue).toBeUndefined(); - * - * // Propagate promise resolution to 'then' functions using $apply(). - * $rootScope.$apply(); - * expect(resolvedValue).toEqual(123); - * })); - * ``` - */ -function $QProvider() { - - this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { - return qFactory(function(callback) { - $rootScope.$evalAsync(callback); - }, $exceptionHandler); - }]; -} - - -/** - * Constructs a promise manager. - * - * @param {function(Function)} nextTick Function for executing functions in the next turn. - * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for - * debugging purposes. - * @returns {object} Promise manager. - */ -function qFactory(nextTick, exceptionHandler) { - - /** - * @ngdoc method - * @name $q#defer - * @kind function - * - * @description - * Creates a `Deferred` object which represents a task which will finish in the future. - * - * @returns {Deferred} Returns a new instance of deferred. - */ - var defer = function() { - var pending = [], - value, deferred; - - deferred = { - - resolve: function(val) { - if (pending) { - var callbacks = pending; - pending = undefined; - value = ref(val); - - if (callbacks.length) { - nextTick(function() { - var callback; - for (var i = 0, ii = callbacks.length; i < ii; i++) { - callback = callbacks[i]; - value.then(callback[0], callback[1], callback[2]); - } - }); - } - } - }, - - - reject: function(reason) { - deferred.resolve(createInternalRejectedPromise(reason)); - }, - - - notify: function(progress) { - if (pending) { - var callbacks = pending; - - if (pending.length) { - nextTick(function() { - var callback; - for (var i = 0, ii = callbacks.length; i < ii; i++) { - callback = callbacks[i]; - callback[2](progress); - } - }); - } - } - }, - - - promise: { - then: function(callback, errback, progressback) { - var result = defer(); - - var wrappedCallback = function(value) { - try { - result.resolve((isFunction(callback) ? callback : defaultCallback)(value)); - } catch(e) { - result.reject(e); - exceptionHandler(e); - } - }; - - var wrappedErrback = function(reason) { - try { - result.resolve((isFunction(errback) ? errback : defaultErrback)(reason)); - } catch(e) { - result.reject(e); - exceptionHandler(e); - } - }; - - var wrappedProgressback = function(progress) { - try { - result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress)); - } catch(e) { - exceptionHandler(e); - } - }; - - if (pending) { - pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]); - } else { - value.then(wrappedCallback, wrappedErrback, wrappedProgressback); - } - - return result.promise; - }, - - "catch": function(callback) { - return this.then(null, callback); - }, - - "finally": function(callback) { - - function makePromise(value, resolved) { - var result = defer(); - if (resolved) { - result.resolve(value); - } else { - result.reject(value); - } - return result.promise; - } - - function handleCallback(value, isResolved) { - var callbackOutput = null; - try { - callbackOutput = (callback ||defaultCallback)(); - } catch(e) { - return makePromise(e, false); - } - if (isPromiseLike(callbackOutput)) { - return callbackOutput.then(function() { - return makePromise(value, isResolved); - }, function(error) { - return makePromise(error, false); - }); - } else { - return makePromise(value, isResolved); - } - } - - return this.then(function(value) { - return handleCallback(value, true); - }, function(error) { - return handleCallback(error, false); - }); - } - } - }; - - return deferred; - }; - - - var ref = function(value) { - if (isPromiseLike(value)) return value; - return { - then: function(callback) { - var result = defer(); - nextTick(function() { - result.resolve(callback(value)); - }); - return result.promise; - } - }; - }; - - - /** - * @ngdoc method - * @name $q#reject - * @kind function - * - * @description - * Creates a promise that is resolved as rejected with the specified `reason`. This api should be - * used to forward rejection in a chain of promises. If you are dealing with the last promise in - * a promise chain, you don't need to worry about it. - * - * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of - * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via - * a promise error callback and you want to forward the error to the promise derived from the - * current promise, you have to "rethrow" the error by returning a rejection constructed via - * `reject`. - * - * ```js - * promiseB = promiseA.then(function(result) { - * // success: do something and resolve promiseB - * // with the old or a new result - * return result; - * }, function(reason) { - * // error: handle the error if possible and - * // resolve promiseB with newPromiseOrValue, - * // otherwise forward the rejection to promiseB - * if (canHandle(reason)) { - * // handle the error and recover - * return newPromiseOrValue; - * } - * return $q.reject(reason); - * }); - * ``` - * - * @param {*} reason Constant, message, exception or an object representing the rejection reason. - * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. - */ - var reject = function(reason) { - var result = defer(); - result.reject(reason); - return result.promise; - }; - - var createInternalRejectedPromise = function(reason) { - return { - then: function(callback, errback) { - var result = defer(); - nextTick(function() { - try { - result.resolve((isFunction(errback) ? errback : defaultErrback)(reason)); - } catch(e) { - result.reject(e); - exceptionHandler(e); - } - }); - return result.promise; - } - }; - }; - - - /** - * @ngdoc method - * @name $q#when - * @kind function - * - * @description - * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. - * This is useful when you are dealing with an object that might or might not be a promise, or if - * the promise comes from a source that can't be trusted. - * - * @param {*} value Value or a promise - * @returns {Promise} Returns a promise of the passed value or promise - */ - var when = function(value, callback, errback, progressback) { - var result = defer(), - done; - - var wrappedCallback = function(value) { - try { - return (isFunction(callback) ? callback : defaultCallback)(value); - } catch (e) { - exceptionHandler(e); - return reject(e); - } - }; - - var wrappedErrback = function(reason) { - try { - return (isFunction(errback) ? errback : defaultErrback)(reason); - } catch (e) { - exceptionHandler(e); - return reject(e); - } - }; - - var wrappedProgressback = function(progress) { - try { - return (isFunction(progressback) ? progressback : defaultCallback)(progress); - } catch (e) { - exceptionHandler(e); - } - }; - - nextTick(function() { - ref(value).then(function(value) { - if (done) return; - done = true; - result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback)); - }, function(reason) { - if (done) return; - done = true; - result.resolve(wrappedErrback(reason)); - }, function(progress) { - if (done) return; - result.notify(wrappedProgressback(progress)); - }); - }); - - return result.promise; - }; - - - function defaultCallback(value) { - return value; - } - - - function defaultErrback(reason) { - return reject(reason); - } - - - /** - * @ngdoc method - * @name $q#all - * @kind function - * - * @description - * Combines multiple promises into a single promise that is resolved when all of the input - * promises are resolved. - * - * @param {Array.|Object.} promises An array or hash of promises. - * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values, - * each value corresponding to the promise at the same index/key in the `promises` array/hash. - * If any of the promises is resolved with a rejection, this resulting promise will be rejected - * with the same rejection value. - */ - function all(promises) { - var deferred = defer(), - counter = 0, - results = isArray(promises) ? [] : {}; - - forEach(promises, function(promise, key) { - counter++; - ref(promise).then(function(value) { - if (results.hasOwnProperty(key)) return; - results[key] = value; - if (!(--counter)) deferred.resolve(results); - }, function(reason) { - if (results.hasOwnProperty(key)) return; - deferred.reject(reason); - }); - }); - - if (counter === 0) { - deferred.resolve(results); - } - - return deferred.promise; - } - - return { - defer: defer, - reject: reject, - when: when, - all: all - }; -} - -function $$RAFProvider(){ //rAF - this.$get = ['$window', '$timeout', function($window, $timeout) { - var requestAnimationFrame = $window.requestAnimationFrame || - $window.webkitRequestAnimationFrame || - $window.mozRequestAnimationFrame; - - var cancelAnimationFrame = $window.cancelAnimationFrame || - $window.webkitCancelAnimationFrame || - $window.mozCancelAnimationFrame || - $window.webkitCancelRequestAnimationFrame; - - var rafSupported = !!requestAnimationFrame; - var raf = rafSupported - ? function(fn) { - var id = requestAnimationFrame(fn); - return function() { - cancelAnimationFrame(id); - }; - } - : function(fn) { - var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 - return function() { - $timeout.cancel(timer); - }; - }; - - raf.supported = rafSupported; - - return raf; - }]; -} - -/** - * DESIGN NOTES - * - * The design decisions behind the scope are heavily favored for speed and memory consumption. - * - * The typical use of scope is to watch the expressions, which most of the time return the same - * value as last time so we optimize the operation. - * - * Closures construction is expensive in terms of speed as well as memory: - * - No closures, instead use prototypical inheritance for API - * - Internal state needs to be stored on scope directly, which means that private state is - * exposed as $$____ properties - * - * Loop operations are optimized by using while(count--) { ... } - * - this means that in order to keep the same order of execution as addition we have to add - * items to the array at the beginning (unshift) instead of at the end (push) - * - * Child scopes are created and removed often - * - Using an array would be slow since inserts in middle are expensive so we use linked list - * - * There are few watches then a lot of observers. This is why you don't want the observer to be - * implemented in the same way as watch. Watch requires return of initialization function which - * are expensive to construct. - */ - - -/** - * @ngdoc provider - * @name $rootScopeProvider - * @description - * - * Provider for the $rootScope service. - */ - -/** - * @ngdoc method - * @name $rootScopeProvider#digestTtl - * @description - * - * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and - * assuming that the model is unstable. - * - * The current default is 10 iterations. - * - * In complex applications it's possible that the dependencies between `$watch`s will result in - * several digest iterations. However if an application needs more than the default 10 digest - * iterations for its model to stabilize then you should investigate what is causing the model to - * continuously change during the digest. - * - * Increasing the TTL could have performance implications, so you should not change it without - * proper justification. - * - * @param {number} limit The number of digest iterations. - */ - - -/** - * @ngdoc service - * @name $rootScope - * @description - * - * Every application has a single root {@link ng.$rootScope.Scope scope}. - * All other scopes are descendant scopes of the root scope. Scopes provide separation - * between the model and the view, via a mechanism for watching the model for changes. - * They also provide an event emission/broadcast and subscription facility. See the - * {@link guide/scope developer guide on scopes}. - */ -function $RootScopeProvider(){ - var TTL = 10; - var $rootScopeMinErr = minErr('$rootScope'); - var lastDirtyWatch = null; - - this.digestTtl = function(value) { - if (arguments.length) { - TTL = value; - } - return TTL; - }; - - this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser', - function( $injector, $exceptionHandler, $parse, $browser) { - - /** - * @ngdoc type - * @name $rootScope.Scope - * - * @description - * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the - * {@link auto.$injector $injector}. Child scopes are created using the - * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when - * compiled HTML template is executed.) - * - * Here is a simple scope snippet to show how you can interact with the scope. - * ```html - * - * ``` - * - * # Inheritance - * A scope can inherit from a parent scope, as in this example: - * ```js - var parent = $rootScope; - var child = parent.$new(); - - parent.salutation = "Hello"; - child.name = "World"; - expect(child.salutation).toEqual('Hello'); - - child.salutation = "Welcome"; - expect(child.salutation).toEqual('Welcome'); - expect(parent.salutation).toEqual('Hello'); - * ``` - * - * - * @param {Object.=} providers Map of service factory which need to be - * provided for the current scope. Defaults to {@link ng}. - * @param {Object.=} instanceCache Provides pre-instantiated services which should - * append/override services provided by `providers`. This is handy - * when unit-testing and having the need to override a default - * service. - * @returns {Object} Newly created scope. - * - */ - function Scope() { - this.$id = nextUid(); - this.$$phase = this.$parent = this.$$watchers = - this.$$nextSibling = this.$$prevSibling = - this.$$childHead = this.$$childTail = null; - this['this'] = this.$root = this; - this.$$destroyed = false; - this.$$asyncQueue = []; - this.$$postDigestQueue = []; - this.$$listeners = {}; - this.$$listenerCount = {}; - this.$$isolateBindings = {}; - } - - /** - * @ngdoc property - * @name $rootScope.Scope#$id - * - * @description - * Unique scope ID (monotonically increasing) useful for debugging. - */ - - /** - * @ngdoc property - * @name $rootScope.Scope#$parent - * - * @description - * Reference to the parent scope. - */ - - /** - * @ngdoc property - * @name $rootScope.Scope#$root - * - * @description - * Reference to the root scope. - */ - - Scope.prototype = { - constructor: Scope, - /** - * @ngdoc method - * @name $rootScope.Scope#$new - * @kind function - * - * @description - * Creates a new child {@link ng.$rootScope.Scope scope}. - * - * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event. - * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. - * - * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is - * desired for the scope and its child scopes to be permanently detached from the parent and - * thus stop participating in model change detection and listener notification by invoking. - * - * @param {boolean} isolate If true, then the scope does not prototypically inherit from the - * parent scope. The scope is isolated, as it can not see parent scope properties. - * When creating widgets, it is useful for the widget to not accidentally read parent - * state. - * - * @returns {Object} The newly created child scope. - * - */ - $new: function(isolate) { - var ChildScope, - child; - - if (isolate) { - child = new Scope(); - child.$root = this.$root; - // ensure that there is just one async queue per $rootScope and its children - child.$$asyncQueue = this.$$asyncQueue; - child.$$postDigestQueue = this.$$postDigestQueue; - } else { - // Only create a child scope class if somebody asks for one, - // but cache it to allow the VM to optimize lookups. - if (!this.$$childScopeClass) { - this.$$childScopeClass = function() { - this.$$watchers = this.$$nextSibling = - this.$$childHead = this.$$childTail = null; - this.$$listeners = {}; - this.$$listenerCount = {}; - this.$id = nextUid(); - this.$$childScopeClass = null; - }; - this.$$childScopeClass.prototype = this; - } - child = new this.$$childScopeClass(); - } - child['this'] = child; - child.$parent = this; - child.$$prevSibling = this.$$childTail; - if (this.$$childHead) { - this.$$childTail.$$nextSibling = child; - this.$$childTail = child; - } else { - this.$$childHead = this.$$childTail = child; - } - return child; - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$watch - * @kind function - * - * @description - * Registers a `listener` callback to be executed whenever the `watchExpression` changes. - * - * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest - * $digest()} and should return the value that will be watched. (Since - * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the - * `watchExpression` can execute multiple times per - * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.) - * - The `listener` is called only when the value from the current `watchExpression` and the - * previous call to `watchExpression` are not equal (with the exception of the initial run, - * see below). Inequality is determined according to reference inequality, - * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators) - * via the `!==` Javascript operator, unless `objectEquality == true` - * (see next point) - * - When `objectEquality == true`, inequality of the `watchExpression` is determined - * according to the {@link angular.equals} function. To save the value of the object for - * later comparison, the {@link angular.copy} function is used. This therefore means that - * watching complex objects will have adverse memory and performance implications. - * - The watch `listener` may change the model, which may trigger other `listener`s to fire. - * This is achieved by rerunning the watchers until no changes are detected. The rerun - * iteration limit is 10 to prevent an infinite loop deadlock. - * - * - * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, - * you can register a `watchExpression` function with no `listener`. (Since `watchExpression` - * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a - * change is detected, be prepared for multiple calls to your listener.) - * - * After a watcher is registered with the scope, the `listener` fn is called asynchronously - * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the - * watcher. In rare cases, this is undesirable because the listener is called when the result - * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you - * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the - * listener was called due to initialization. - * - * The example below contains an illustration of using a function as your $watch listener - * - * - * # Example - * ```js - // let's assume that scope was dependency injected as the $rootScope - var scope = $rootScope; - scope.name = 'misko'; - scope.counter = 0; - - expect(scope.counter).toEqual(0); - scope.$watch('name', function(newValue, oldValue) { - scope.counter = scope.counter + 1; - }); - expect(scope.counter).toEqual(0); - - scope.$digest(); - // the listener is always called during the first $digest loop after it was registered - expect(scope.counter).toEqual(1); - - scope.$digest(); - // but now it will not be called unless the value changes - expect(scope.counter).toEqual(1); - - scope.name = 'adam'; - scope.$digest(); - expect(scope.counter).toEqual(2); - - - - // Using a listener function - var food; - scope.foodCounter = 0; - expect(scope.foodCounter).toEqual(0); - scope.$watch( - // This is the listener function - function() { return food; }, - // This is the change handler - function(newValue, oldValue) { - if ( newValue !== oldValue ) { - // Only increment the counter if the value changed - scope.foodCounter = scope.foodCounter + 1; - } - } - ); - // No digest has been run so the counter will be zero - expect(scope.foodCounter).toEqual(0); - - // Run the digest but since food has not changed count will still be zero - scope.$digest(); - expect(scope.foodCounter).toEqual(0); - - // Update food and run digest. Now the counter will increment - food = 'cheeseburger'; - scope.$digest(); - expect(scope.foodCounter).toEqual(1); - - * ``` - * - * - * - * @param {(function()|string)} watchExpression Expression that is evaluated on each - * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers - * a call to the `listener`. - * - * - `string`: Evaluated as {@link guide/expression expression} - * - `function(scope)`: called with current `scope` as a parameter. - * @param {(function()|string)=} listener Callback called whenever the return value of - * the `watchExpression` changes. - * - * - `string`: Evaluated as {@link guide/expression expression} - * - `function(newValue, oldValue, scope)`: called with current and previous values as - * parameters. - * - * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of - * comparing for reference equality. - * @returns {function()} Returns a deregistration function for this listener. - */ - $watch: function(watchExp, listener, objectEquality) { - var scope = this, - get = compileToFn(watchExp, 'watch'), - array = scope.$$watchers, - watcher = { - fn: listener, - last: initWatchVal, - get: get, - exp: watchExp, - eq: !!objectEquality - }; - - lastDirtyWatch = null; - - // in the case user pass string, we need to compile it, do we really need this ? - if (!isFunction(listener)) { - var listenFn = compileToFn(listener || noop, 'listener'); - watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);}; - } - - if (typeof watchExp == 'string' && get.constant) { - var originalFn = watcher.fn; - watcher.fn = function(newVal, oldVal, scope) { - originalFn.call(this, newVal, oldVal, scope); - arrayRemove(array, watcher); - }; - } - - if (!array) { - array = scope.$$watchers = []; - } - // we use unshift since we use a while loop in $digest for speed. - // the while loop reads in reverse order. - array.unshift(watcher); - - return function deregisterWatch() { - arrayRemove(array, watcher); - lastDirtyWatch = null; - }; - }, - - - /** - * @ngdoc method - * @name $rootScope.Scope#$watchCollection - * @kind function - * - * @description - * Shallow watches the properties of an object and fires whenever any of the properties change - * (for arrays, this implies watching the array items; for object maps, this implies watching - * the properties). If a change is detected, the `listener` callback is fired. - * - * - The `obj` collection is observed via standard $watch operation and is examined on every - * call to $digest() to see if any items have been added, removed, or moved. - * - The `listener` is called whenever anything within the `obj` has changed. Examples include - * adding, removing, and moving items belonging to an object or array. - * - * - * # Example - * ```js - $scope.names = ['igor', 'matias', 'misko', 'james']; - $scope.dataCount = 4; - - $scope.$watchCollection('names', function(newNames, oldNames) { - $scope.dataCount = newNames.length; - }); - - expect($scope.dataCount).toEqual(4); - $scope.$digest(); - - //still at 4 ... no changes - expect($scope.dataCount).toEqual(4); - - $scope.names.pop(); - $scope.$digest(); - - //now there's been a change - expect($scope.dataCount).toEqual(3); - * ``` - * - * - * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The - * expression value should evaluate to an object or an array which is observed on each - * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the - * collection will trigger a call to the `listener`. - * - * @param {function(newCollection, oldCollection, scope)} listener a callback function called - * when a change is detected. - * - The `newCollection` object is the newly modified data obtained from the `obj` expression - * - The `oldCollection` object is a copy of the former collection data. - * Due to performance considerations, the`oldCollection` value is computed only if the - * `listener` function declares two or more arguments. - * - The `scope` argument refers to the current scope. - * - * @returns {function()} Returns a de-registration function for this listener. When the - * de-registration function is executed, the internal watch operation is terminated. - */ - $watchCollection: function(obj, listener) { - var self = this; - // the current value, updated on each dirty-check run - var newValue; - // a shallow copy of the newValue from the last dirty-check run, - // updated to match newValue during dirty-check run - var oldValue; - // a shallow copy of the newValue from when the last change happened - var veryOldValue; - // only track veryOldValue if the listener is asking for it - var trackVeryOldValue = (listener.length > 1); - var changeDetected = 0; - var objGetter = $parse(obj); - var internalArray = []; - var internalObject = {}; - var initRun = true; - var oldLength = 0; - - function $watchCollectionWatch() { - newValue = objGetter(self); - var newLength, key, bothNaN; - - if (!isObject(newValue)) { // if primitive - if (oldValue !== newValue) { - oldValue = newValue; - changeDetected++; - } - } else if (isArrayLike(newValue)) { - if (oldValue !== internalArray) { - // we are transitioning from something which was not an array into array. - oldValue = internalArray; - oldLength = oldValue.length = 0; - changeDetected++; - } - - newLength = newValue.length; - - if (oldLength !== newLength) { - // if lengths do not match we need to trigger change notification - changeDetected++; - oldValue.length = oldLength = newLength; - } - // copy the items to oldValue and look for changes. - for (var i = 0; i < newLength; i++) { - bothNaN = (oldValue[i] !== oldValue[i]) && - (newValue[i] !== newValue[i]); - if (!bothNaN && (oldValue[i] !== newValue[i])) { - changeDetected++; - oldValue[i] = newValue[i]; - } - } - } else { - if (oldValue !== internalObject) { - // we are transitioning from something which was not an object into object. - oldValue = internalObject = {}; - oldLength = 0; - changeDetected++; - } - // copy the items to oldValue and look for changes. - newLength = 0; - for (key in newValue) { - if (newValue.hasOwnProperty(key)) { - newLength++; - if (oldValue.hasOwnProperty(key)) { - bothNaN = (oldValue[key] !== oldValue[key]) && - (newValue[key] !== newValue[key]); - if (!bothNaN && (oldValue[key] !== newValue[key])) { - changeDetected++; - oldValue[key] = newValue[key]; - } - } else { - oldLength++; - oldValue[key] = newValue[key]; - changeDetected++; - } - } - } - if (oldLength > newLength) { - // we used to have more keys, need to find them and destroy them. - changeDetected++; - for(key in oldValue) { - if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) { - oldLength--; - delete oldValue[key]; - } - } - } - } - return changeDetected; - } - - function $watchCollectionAction() { - if (initRun) { - initRun = false; - listener(newValue, newValue, self); - } else { - listener(newValue, veryOldValue, self); - } - - // make a copy for the next time a collection is changed - if (trackVeryOldValue) { - if (!isObject(newValue)) { - //primitive - veryOldValue = newValue; - } else if (isArrayLike(newValue)) { - veryOldValue = new Array(newValue.length); - for (var i = 0; i < newValue.length; i++) { - veryOldValue[i] = newValue[i]; - } - } else { // if object - veryOldValue = {}; - for (var key in newValue) { - if (hasOwnProperty.call(newValue, key)) { - veryOldValue[key] = newValue[key]; - } - } - } - } - } - - return this.$watch($watchCollectionWatch, $watchCollectionAction); - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$digest - * @kind function - * - * @description - * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and - * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change - * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} - * until no more listeners are firing. This means that it is possible to get into an infinite - * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of - * iterations exceeds 10. - * - * Usually, you don't call `$digest()` directly in - * {@link ng.directive:ngController controllers} or in - * {@link ng.$compileProvider#directive directives}. - * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within - * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`. - * - * If you want to be notified whenever `$digest()` is called, - * you can register a `watchExpression` function with - * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. - * - * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. - * - * # Example - * ```js - var scope = ...; - scope.name = 'misko'; - scope.counter = 0; - - expect(scope.counter).toEqual(0); - scope.$watch('name', function(newValue, oldValue) { - scope.counter = scope.counter + 1; - }); - expect(scope.counter).toEqual(0); - - scope.$digest(); - // the listener is always called during the first $digest loop after it was registered - expect(scope.counter).toEqual(1); - - scope.$digest(); - // but now it will not be called unless the value changes - expect(scope.counter).toEqual(1); - - scope.name = 'adam'; - scope.$digest(); - expect(scope.counter).toEqual(2); - * ``` - * - */ - $digest: function() { - var watch, value, last, - watchers, - asyncQueue = this.$$asyncQueue, - postDigestQueue = this.$$postDigestQueue, - length, - dirty, ttl = TTL, - next, current, target = this, - watchLog = [], - logIdx, logMsg, asyncTask; - - beginPhase('$digest'); - // Check for changes to browser url that happened in sync before the call to $digest - $browser.$$checkUrlChange(); - - lastDirtyWatch = null; - - do { // "while dirty" loop - dirty = false; - current = target; - - while(asyncQueue.length) { - try { - asyncTask = asyncQueue.shift(); - asyncTask.scope.$eval(asyncTask.expression); - } catch (e) { - clearPhase(); - $exceptionHandler(e); - } - lastDirtyWatch = null; - } - - traverseScopesLoop: - do { // "traverse the scopes" loop - if ((watchers = current.$$watchers)) { - // process our watches - length = watchers.length; - while (length--) { - try { - watch = watchers[length]; - // Most common watches are on primitives, in which case we can short - // circuit it with === operator, only when === fails do we use .equals - if (watch) { - if ((value = watch.get(current)) !== (last = watch.last) && - !(watch.eq - ? equals(value, last) - : (typeof value === 'number' && typeof last === 'number' - && isNaN(value) && isNaN(last)))) { - dirty = true; - lastDirtyWatch = watch; - watch.last = watch.eq ? copy(value, null) : value; - watch.fn(value, ((last === initWatchVal) ? value : last), current); - if (ttl < 5) { - logIdx = 4 - ttl; - if (!watchLog[logIdx]) watchLog[logIdx] = []; - logMsg = (isFunction(watch.exp)) - ? 'fn: ' + (watch.exp.name || watch.exp.toString()) - : watch.exp; - logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last); - watchLog[logIdx].push(logMsg); - } - } else if (watch === lastDirtyWatch) { - // If the most recently dirty watcher is now clean, short circuit since the remaining watchers - // have already been tested. - dirty = false; - break traverseScopesLoop; - } - } - } catch (e) { - clearPhase(); - $exceptionHandler(e); - } - } - } - - // Insanity Warning: scope depth-first traversal - // yes, this code is a bit crazy, but it works and we have tests to prove it! - // this piece should be kept in sync with the traversal in $broadcast - if (!(next = (current.$$childHead || - (current !== target && current.$$nextSibling)))) { - while(current !== target && !(next = current.$$nextSibling)) { - current = current.$parent; - } - } - } while ((current = next)); - - // `break traverseScopesLoop;` takes us to here - - if((dirty || asyncQueue.length) && !(ttl--)) { - clearPhase(); - throw $rootScopeMinErr('infdig', - '{0} $digest() iterations reached. Aborting!\n' + - 'Watchers fired in the last 5 iterations: {1}', - TTL, toJson(watchLog)); - } - - } while (dirty || asyncQueue.length); - - clearPhase(); - - while(postDigestQueue.length) { - try { - postDigestQueue.shift()(); - } catch (e) { - $exceptionHandler(e); - } - } - }, - - - /** - * @ngdoc event - * @name $rootScope.Scope#$destroy - * @eventType broadcast on scope being destroyed - * - * @description - * Broadcasted when a scope and its children are being destroyed. - * - * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to - * clean up DOM bindings before an element is removed from the DOM. - */ - - /** - * @ngdoc method - * @name $rootScope.Scope#$destroy - * @kind function - * - * @description - * Removes the current scope (and all of its children) from the parent scope. Removal implies - * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer - * propagate to the current scope and its children. Removal also implies that the current - * scope is eligible for garbage collection. - * - * The `$destroy()` is usually used by directives such as - * {@link ng.directive:ngRepeat ngRepeat} for managing the - * unrolling of the loop. - * - * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope. - * Application code can register a `$destroy` event handler that will give it a chance to - * perform any necessary cleanup. - * - * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to - * clean up DOM bindings before an element is removed from the DOM. - */ - $destroy: function() { - // we can't destroy the root scope or a scope that has been already destroyed - if (this.$$destroyed) return; - var parent = this.$parent; - - this.$broadcast('$destroy'); - this.$$destroyed = true; - if (this === $rootScope) return; - - forEach(this.$$listenerCount, bind(null, decrementListenerCount, this)); - - // sever all the references to parent scopes (after this cleanup, the current scope should - // not be retained by any of our references and should be eligible for garbage collection) - if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; - if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; - if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; - if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; - - - // All of the code below is bogus code that works around V8's memory leak via optimized code - // and inline caches. - // - // see: - // - https://code.google.com/p/v8/issues/detail?id=2073#c26 - // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909 - // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 - - this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = - this.$$childTail = this.$root = null; - - // don't reset these to null in case some async task tries to register a listener/watch/task - this.$$listeners = {}; - this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = []; - - // prevent NPEs since these methods have references to properties we nulled out - this.$destroy = this.$digest = this.$apply = noop; - this.$on = this.$watch = function() { return noop; }; - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$eval - * @kind function - * - * @description - * Executes the `expression` on the current scope and returns the result. Any exceptions in - * the expression are propagated (uncaught). This is useful when evaluating Angular - * expressions. - * - * # Example - * ```js - var scope = ng.$rootScope.Scope(); - scope.a = 1; - scope.b = 2; - - expect(scope.$eval('a+b')).toEqual(3); - expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); - * ``` - * - * @param {(string|function())=} expression An angular expression to be executed. - * - * - `string`: execute using the rules as defined in {@link guide/expression expression}. - * - `function(scope)`: execute the function with the current `scope` parameter. - * - * @param {(object)=} locals Local variables object, useful for overriding values in scope. - * @returns {*} The result of evaluating the expression. - */ - $eval: function(expr, locals) { - return $parse(expr)(this, locals); - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$evalAsync - * @kind function - * - * @description - * Executes the expression on the current scope at a later point in time. - * - * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only - * that: - * - * - it will execute after the function that scheduled the evaluation (preferably before DOM - * rendering). - * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after - * `expression` execution. - * - * Any exceptions from the execution of the expression are forwarded to the - * {@link ng.$exceptionHandler $exceptionHandler} service. - * - * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle - * will be scheduled. However, it is encouraged to always call code that changes the model - * from within an `$apply` call. That includes code evaluated via `$evalAsync`. - * - * @param {(string|function())=} expression An angular expression to be executed. - * - * - `string`: execute using the rules as defined in {@link guide/expression expression}. - * - `function(scope)`: execute the function with the current `scope` parameter. - * - */ - $evalAsync: function(expr) { - // if we are outside of an $digest loop and this is the first time we are scheduling async - // task also schedule async auto-flush - if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) { - $browser.defer(function() { - if ($rootScope.$$asyncQueue.length) { - $rootScope.$digest(); - } - }); - } - - this.$$asyncQueue.push({scope: this, expression: expr}); - }, - - $$postDigest : function(fn) { - this.$$postDigestQueue.push(fn); - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$apply - * @kind function - * - * @description - * `$apply()` is used to execute an expression in angular from outside of the angular - * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). - * Because we are calling into the angular framework we need to perform proper scope life - * cycle of {@link ng.$exceptionHandler exception handling}, - * {@link ng.$rootScope.Scope#$digest executing watches}. - * - * ## Life cycle - * - * # Pseudo-Code of `$apply()` - * ```js - function $apply(expr) { - try { - return $eval(expr); - } catch (e) { - $exceptionHandler(e); - } finally { - $root.$digest(); - } - } - * ``` - * - * - * Scope's `$apply()` method transitions through the following stages: - * - * 1. The {@link guide/expression expression} is executed using the - * {@link ng.$rootScope.Scope#$eval $eval()} method. - * 2. Any exceptions from the execution of the expression are forwarded to the - * {@link ng.$exceptionHandler $exceptionHandler} service. - * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the - * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. - * - * - * @param {(string|function())=} exp An angular expression to be executed. - * - * - `string`: execute using the rules as defined in {@link guide/expression expression}. - * - `function(scope)`: execute the function with current `scope` parameter. - * - * @returns {*} The result of evaluating the expression. - */ - $apply: function(expr) { - try { - beginPhase('$apply'); - return this.$eval(expr); - } catch (e) { - $exceptionHandler(e); - } finally { - clearPhase(); - try { - $rootScope.$digest(); - } catch (e) { - $exceptionHandler(e); - throw e; - } - } - }, - - /** - * @ngdoc method - * @name $rootScope.Scope#$on - * @kind function - * - * @description - * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for - * discussion of event life cycle. - * - * The event listener function format is: `function(event, args...)`. The `event` object - * passed into the listener has the following attributes: - * - * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or - * `$broadcast`-ed. - * - `currentScope` - `{Scope}`: the current scope which is handling the event. - * - `name` - `{string}`: name of the event. - * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel - * further event propagation (available only for events that were `$emit`-ed). - * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag - * to true. - * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. - * - * @param {string} name Event name to listen on. - * @param {function(event, ...args)} listener Function to call when the event is emitted. - * @returns {function()} Returns a deregistration function for this listener. - */ - $on: function(name, listener) { - var namedListeners = this.$$listeners[name]; - if (!namedListeners) { - this.$$listeners[name] = namedListeners = []; - } - namedListeners.push(listener); - - var current = this; - do { - if (!current.$$listenerCount[name]) { - current.$$listenerCount[name] = 0; - } - current.$$listenerCount[name]++; - } while ((current = current.$parent)); - - var self = this; - return function() { - var indexOfListener = indexOf(namedListeners, listener); - if (indexOfListener !== -1) { - namedListeners[indexOfListener] = null; - decrementListenerCount(self, 1, name); - } - }; - }, - - - /** - * @ngdoc method - * @name $rootScope.Scope#$emit - * @kind function - * - * @description - * Dispatches an event `name` upwards through the scope hierarchy notifying the - * registered {@link ng.$rootScope.Scope#$on} listeners. - * - * The event life cycle starts at the scope on which `$emit` was called. All - * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get - * notified. Afterwards, the event traverses upwards toward the root scope and calls all - * registered listeners along the way. The event will stop propagating if one of the listeners - * cancels it. - * - * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed - * onto the {@link ng.$exceptionHandler $exceptionHandler} service. - * - * @param {string} name Event name to emit. - * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. - * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). - */ - $emit: function(name, args) { - var empty = [], - namedListeners, - scope = this, - stopPropagation = false, - event = { - name: name, - targetScope: scope, - stopPropagation: function() {stopPropagation = true;}, - preventDefault: function() { - event.defaultPrevented = true; - }, - defaultPrevented: false - }, - listenerArgs = concat([event], arguments, 1), - i, length; - - do { - namedListeners = scope.$$listeners[name] || empty; - event.currentScope = scope; - for (i=0, length=namedListeners.length; i= 8 ) { - normalizedVal = urlResolve(uri).href; - if (normalizedVal !== '' && !normalizedVal.match(regex)) { - return 'unsafe:'+normalizedVal; - } - } - return uri; - }; - }; -} - -var $sceMinErr = minErr('$sce'); - -var SCE_CONTEXTS = { - HTML: 'html', - CSS: 'css', - URL: 'url', - // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a - // url. (e.g. ng-include, script src, templateUrl) - RESOURCE_URL: 'resourceUrl', - JS: 'js' -}; - -// Helper functions follow. - -// Copied from: -// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962 -// Prereq: s is a string. -function escapeForRegexp(s) { - return s.replace(/([-()\[\]{}+?*.$\^|,:# -1) { - throw $sceMinErr('iwcard', - 'Illegal sequence *** in string matcher. String: {0}', matcher); - } - matcher = escapeForRegexp(matcher). - replace('\\*\\*', '.*'). - replace('\\*', '[^:/.?&;]*'); - return new RegExp('^' + matcher + '$'); - } else if (isRegExp(matcher)) { - // The only other type of matcher allowed is a Regexp. - // Match entire URL / disallow partial matches. - // Flags are reset (i.e. no global, ignoreCase or multiline) - return new RegExp('^' + matcher.source + '$'); - } else { - throw $sceMinErr('imatcher', - 'Matchers may only be "self", string patterns or RegExp objects'); - } -} - - -function adjustMatchers(matchers) { - var adjustedMatchers = []; - if (isDefined(matchers)) { - forEach(matchers, function(matcher) { - adjustedMatchers.push(adjustMatcher(matcher)); - }); - } - return adjustedMatchers; -} - - -/** - * @ngdoc service - * @name $sceDelegate - * @kind function - * - * @description - * - * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict - * Contextual Escaping (SCE)} services to AngularJS. - * - * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of - * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is - * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to - * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things - * work because `$sce` delegates to `$sceDelegate` for these operations. - * - * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service. - * - * The default instance of `$sceDelegate` should work out of the box with little pain. While you - * can override it completely to change the behavior of `$sce`, the common case would - * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting - * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as - * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist - * $sceDelegateProvider.resourceUrlWhitelist} and {@link - * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} - */ - -/** - * @ngdoc provider - * @name $sceDelegateProvider - * @description - * - * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate - * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure - * that the URLs used for sourcing Angular templates are safe. Refer {@link - * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and - * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} - * - * For the general details about this service in Angular, read the main page for {@link ng.$sce - * Strict Contextual Escaping (SCE)}. - * - * **Example**: Consider the following case. - * - * - your app is hosted at url `http://myapp.example.com/` - * - but some of your templates are hosted on other domains you control such as - * `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc. - * - and you have an open redirect at `http://myapp.example.com/clickThru?...`. - * - * Here is what a secure configuration for this scenario might look like: - * - * ``` - * angular.module('myApp', []).config(function($sceDelegateProvider) { - * $sceDelegateProvider.resourceUrlWhitelist([ - * // Allow same origin resource loads. - * 'self', - * // Allow loading from our assets domain. Notice the difference between * and **. - * 'http://srv*.assets.example.com/**' - * ]); - * - * // The blacklist overrides the whitelist so the open redirect here is blocked. - * $sceDelegateProvider.resourceUrlBlacklist([ - * 'http://myapp.example.com/clickThru**' - * ]); - * }); - * ``` - */ - -function $SceDelegateProvider() { - this.SCE_CONTEXTS = SCE_CONTEXTS; - - // Resource URLs can also be trusted by policy. - var resourceUrlWhitelist = ['self'], - resourceUrlBlacklist = []; - - /** - * @ngdoc method - * @name $sceDelegateProvider#resourceUrlWhitelist - * @kind function - * - * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value - * provided. This must be an array or null. A snapshot of this array is used so further - * changes to the array are ignored. - * - * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items - * allowed in this array. - * - * Note: **an empty whitelist array will block all URLs**! - * - * @return {Array} the currently set whitelist array. - * - * The **default value** when no whitelist has been explicitly set is `['self']` allowing only - * same origin resource requests. - * - * @description - * Sets/Gets the whitelist of trusted resource URLs. - */ - this.resourceUrlWhitelist = function (value) { - if (arguments.length) { - resourceUrlWhitelist = adjustMatchers(value); - } - return resourceUrlWhitelist; - }; - - /** - * @ngdoc method - * @name $sceDelegateProvider#resourceUrlBlacklist - * @kind function - * - * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value - * provided. This must be an array or null. A snapshot of this array is used so further - * changes to the array are ignored. - * - * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items - * allowed in this array. - * - * The typical usage for the blacklist is to **block - * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as - * these would otherwise be trusted but actually return content from the redirected domain. - * - * Finally, **the blacklist overrides the whitelist** and has the final say. - * - * @return {Array} the currently set blacklist array. - * - * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there - * is no blacklist.) - * - * @description - * Sets/Gets the blacklist of trusted resource URLs. - */ - - this.resourceUrlBlacklist = function (value) { - if (arguments.length) { - resourceUrlBlacklist = adjustMatchers(value); - } - return resourceUrlBlacklist; - }; - - this.$get = ['$injector', function($injector) { - - var htmlSanitizer = function htmlSanitizer(html) { - throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); - }; - - if ($injector.has('$sanitize')) { - htmlSanitizer = $injector.get('$sanitize'); - } - - - function matchUrl(matcher, parsedUrl) { - if (matcher === 'self') { - return urlIsSameOrigin(parsedUrl); - } else { - // definitely a regex. See adjustMatchers() - return !!matcher.exec(parsedUrl.href); - } - } - - function isResourceUrlAllowedByPolicy(url) { - var parsedUrl = urlResolve(url.toString()); - var i, n, allowed = false; - // Ensure that at least one item from the whitelist allows this url. - for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) { - if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) { - allowed = true; - break; - } - } - if (allowed) { - // Ensure that no item from the blacklist blocked this url. - for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) { - if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) { - allowed = false; - break; - } - } - } - return allowed; - } - - function generateHolderType(Base) { - var holderType = function TrustedValueHolderType(trustedValue) { - this.$$unwrapTrustedValue = function() { - return trustedValue; - }; - }; - if (Base) { - holderType.prototype = new Base(); - } - holderType.prototype.valueOf = function sceValueOf() { - return this.$$unwrapTrustedValue(); - }; - holderType.prototype.toString = function sceToString() { - return this.$$unwrapTrustedValue().toString(); - }; - return holderType; - } - - var trustedValueHolderBase = generateHolderType(), - byType = {}; - - byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase); - byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase); - byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase); - byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase); - byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]); - - /** - * @ngdoc method - * @name $sceDelegate#trustAs - * - * @description - * Returns an object that is trusted by angular for use in specified strict - * contextual escaping contexts (such as ng-bind-html, ng-include, any src - * attribute interpolation, any dom event binding attribute interpolation - * such as for onclick, etc.) that uses the provided value. - * See {@link ng.$sce $sce} for enabling strict contextual escaping. - * - * @param {string} type The kind of context in which this value is safe for use. e.g. url, - * resourceUrl, html, js and css. - * @param {*} value The value that that should be considered trusted/safe. - * @returns {*} A value that can be used to stand in for the provided `value` in places - * where Angular expects a $sce.trustAs() return value. - */ - function trustAs(type, trustedValue) { - var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); - if (!Constructor) { - throw $sceMinErr('icontext', - 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}', - type, trustedValue); - } - if (trustedValue === null || trustedValue === undefined || trustedValue === '') { - return trustedValue; - } - // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting - // mutable objects, we ensure here that the value passed in is actually a string. - if (typeof trustedValue !== 'string') { - throw $sceMinErr('itype', - 'Attempted to trust a non-string value in a content requiring a string: Context: {0}', - type); - } - return new Constructor(trustedValue); - } - - /** - * @ngdoc method - * @name $sceDelegate#valueOf - * - * @description - * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs - * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link - * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. - * - * If the passed parameter is not a value that had been returned by {@link - * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is. - * - * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} - * call or anything else. - * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs - * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns - * `value` unchanged. - */ - function valueOf(maybeTrusted) { - if (maybeTrusted instanceof trustedValueHolderBase) { - return maybeTrusted.$$unwrapTrustedValue(); - } else { - return maybeTrusted; - } - } - - /** - * @ngdoc method - * @name $sceDelegate#getTrusted - * - * @description - * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and - * returns the originally supplied value if the queried context type is a supertype of the - * created type. If this condition isn't satisfied, throws an exception. - * - * @param {string} type The kind of context in which this value is to be used. - * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs - * `$sceDelegate.trustAs`} call. - * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs - * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. - */ - function getTrusted(type, maybeTrusted) { - if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') { - return maybeTrusted; - } - var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); - if (constructor && maybeTrusted instanceof constructor) { - return maybeTrusted.$$unwrapTrustedValue(); - } - // If we get here, then we may only take one of two actions. - // 1. sanitize the value for the requested type, or - // 2. throw an exception. - if (type === SCE_CONTEXTS.RESOURCE_URL) { - if (isResourceUrlAllowedByPolicy(maybeTrusted)) { - return maybeTrusted; - } else { - throw $sceMinErr('insecurl', - 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', - maybeTrusted.toString()); - } - } else if (type === SCE_CONTEXTS.HTML) { - return htmlSanitizer(maybeTrusted); - } - throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); - } - - return { trustAs: trustAs, - getTrusted: getTrusted, - valueOf: valueOf }; - }]; -} - - -/** - * @ngdoc provider - * @name $sceProvider - * @description - * - * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. - * - enable/disable Strict Contextual Escaping (SCE) in a module - * - override the default implementation with a custom delegate - * - * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}. - */ - -/* jshint maxlen: false*/ - -/** - * @ngdoc service - * @name $sce - * @kind function - * - * @description - * - * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. - * - * # Strict Contextual Escaping - * - * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain - * contexts to result in a value that is marked as safe to use for that context. One example of - * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer - * to these contexts as privileged or SCE contexts. - * - * As of version 1.2, Angular ships with SCE enabled by default. - * - * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows - * one to execute arbitrary javascript by the use of the expression() syntax. Refer - * to learn more about them. - * You can ensure your document is in standards mode and not quirks mode by adding `` - * to the top of your HTML document. - * - * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for - * security vulnerabilities such as XSS, clickjacking, etc. a lot easier. - * - * Here's an example of a binding in a privileged context: - * - * ``` - * - *
- * ``` - * - * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE - * disabled, this application allows the user to render arbitrary HTML into the DIV. - * In a more realistic example, one may be rendering user comments, blog articles, etc. via - * bindings. (HTML is just one example of a context where rendering user controlled input creates - * security vulnerabilities.) - * - * For the case of HTML, you might use a library, either on the client side, or on the server side, - * to sanitize unsafe HTML before binding to the value and rendering it in the document. - * - * How would you ensure that every place that used these types of bindings was bound to a value that - * was sanitized by your library (or returned as safe for rendering by your server?) How can you - * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some - * properties/fields and forgot to update the binding to the sanitized value? - * - * To be secure by default, you want to ensure that any such bindings are disallowed unless you can - * determine that something explicitly says it's safe to use a value for binding in that - * context. You can then audit your code (a simple grep would do) to ensure that this is only done - * for those values that you can easily tell are safe - because they were received from your server, - * sanitized by your library, etc. You can organize your codebase to help with this - perhaps - * allowing only the files in a specific directory to do this. Ensuring that the internal API - * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. - * - * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} - * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to - * obtain values that will be accepted by SCE / privileged contexts. - * - * - * ## How does it work? - * - * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted - * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link - * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the - * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. - * - * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link - * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly - * simplified): - * - * ``` - * var ngBindHtmlDirective = ['$sce', function($sce) { - * return function(scope, element, attr) { - * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) { - * element.html(value || ''); - * }); - * }; - * }]; - * ``` - * - * ## Impact on loading templates - * - * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as - * `templateUrl`'s specified by {@link guide/directive directives}. - * - * By default, Angular only loads templates from the same domain and protocol as the application - * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl - * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or - * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist - * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value. - * - * *Please note*: - * The browser's - * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) - * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/) - * policy apply in addition to this and may further restrict whether the template is successfully - * loaded. This means that without the right CORS policy, loading templates from a different domain - * won't work on all browsers. Also, loading templates from `file://` URL does not work on some - * browsers. - * - * ## This feels like too much overhead for the developer? - * - * It's important to remember that SCE only applies to interpolation expressions. - * - * If your expressions are constant literals, they're automatically trusted and you don't need to - * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g. - * `
`) just works. - * - * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them - * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here. - * - * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load - * templates in `ng-include` from your application's domain without having to even know about SCE. - * It blocks loading templates from other domains or loading templates over http from an https - * served document. You can change these by setting your own custom {@link - * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link - * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs. - * - * This significantly reduces the overhead. It is far easier to pay the small overhead and have an - * application that's secure and can be audited to verify that with much more ease than bolting - * security onto an application later. - * - * - * ## What trusted context types are supported? - * - * | Context | Notes | - * |---------------------|----------------| - * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. | - * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | - * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | - * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | - * - * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist}
- * - * Each element in these arrays must be one of the following: - * - * - **'self'** - * - The special **string**, `'self'`, can be used to match against all URLs of the **same - * domain** as the application document using the **same protocol**. - * - **String** (except the special value `'self'`) - * - The string is matched against the full *normalized / absolute URL* of the resource - * being tested (substring matches are not good enough.) - * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters - * match themselves. - * - `*`: matches zero or more occurrences of any character other than one of the following 6 - * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use - * in a whitelist. - * - `**`: matches zero or more occurrences of *any* character. As such, it's not - * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g. - * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might - * not have been the intention.) Its usage at the very end of the path is ok. (e.g. - * http://foo.example.com/templates/**). - * - **RegExp** (*see caveat below*) - * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax - * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to - * accidentally introduce a bug when one updates a complex expression (imho, all regexes should - * have good test coverage.). For instance, the use of `.` in the regex is correct only in a - * small number of cases. A `.` character in the regex used when matching the scheme or a - * subdomain could be matched against a `:` or literal `.` that was likely not intended. It - * is highly recommended to use the string patterns and only fall back to regular expressions - * if they as a last resort. - * - The regular expression must be an instance of RegExp (i.e. not a string.) It is - * matched against the **entire** *normalized / absolute URL* of the resource being tested - * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags - * present on the RegExp (such as multiline, global, ignoreCase) are ignored. - * - If you are generating your JavaScript from some other templating engine (not - * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)), - * remember to escape your regular expression (and be aware that you might need more than - * one level of escaping depending on your templating engine and the way you interpolated - * the value.) Do make use of your platform's escaping mechanism as it might be good - * enough before coding your own. e.g. Ruby has - * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape) - * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape). - * Javascript lacks a similar built in function for escaping. Take a look at Google - * Closure library's [goog.string.regExpEscape(s)]( - * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962). - * - * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. - * - * ## Show me an example using SCE. - * - * - * - *
- *

- * User comments
- * By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when - * $sanitize is available. If $sanitize isn't available, this results in an error instead of an - * exploit. - *
- *
- * {{userComment.name}}: - * - *
- *
- *
- *
- *
- * - * - * var mySceApp = angular.module('mySceApp', ['ngSanitize']); - * - * mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) { - * var self = this; - * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) { - * self.userComments = userComments; - * }); - * self.explicitlyTrustedHtml = $sce.trustAsHtml( - * 'Hover over this text.'); - * }); - * - * - * - * [ - * { "name": "Alice", - * "htmlComment": - * "Is anyone reading this?" - * }, - * { "name": "Bob", - * "htmlComment": "Yes! Am I the only other one?" - * } - * ] - * - * - * - * describe('SCE doc demo', function() { - * it('should sanitize untrusted values', function() { - * expect(element.all(by.css('.htmlComment')).first().getInnerHtml()) - * .toBe('Is anyone reading this?'); - * }); - * - * it('should NOT sanitize explicitly trusted values', function() { - * expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe( - * 'Hover over this text.'); - * }); - * }); - * - *
- * - * - * - * ## Can I disable SCE completely? - * - * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits - * for little coding overhead. It will be much harder to take an SCE disabled application and - * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE - * for cases where you have a lot of existing code that was written before SCE was introduced and - * you're migrating them a module at a time. - * - * That said, here's how you can completely disable SCE: - * - * ``` - * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) { - * // Completely disable SCE. For demonstration purposes only! - * // Do not use in new projects. - * $sceProvider.enabled(false); - * }); - * ``` - * - */ -/* jshint maxlen: 100 */ - -function $SceProvider() { - var enabled = true; - - /** - * @ngdoc method - * @name $sceProvider#enabled - * @kind function - * - * @param {boolean=} value If provided, then enables/disables SCE. - * @return {boolean} true if SCE is enabled, false otherwise. - * - * @description - * Enables/disables SCE and returns the current value. - */ - this.enabled = function (value) { - if (arguments.length) { - enabled = !!value; - } - return enabled; - }; - - - /* Design notes on the default implementation for SCE. - * - * The API contract for the SCE delegate - * ------------------------------------- - * The SCE delegate object must provide the following 3 methods: - * - * - trustAs(contextEnum, value) - * This method is used to tell the SCE service that the provided value is OK to use in the - * contexts specified by contextEnum. It must return an object that will be accepted by - * getTrusted() for a compatible contextEnum and return this value. - * - * - valueOf(value) - * For values that were not produced by trustAs(), return them as is. For values that were - * produced by trustAs(), return the corresponding input value to trustAs. Basically, if - * trustAs is wrapping the given values into some type, this operation unwraps it when given - * such a value. - * - * - getTrusted(contextEnum, value) - * This function should return the a value that is safe to use in the context specified by - * contextEnum or throw and exception otherwise. - * - * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be - * opaque or wrapped in some holder object. That happens to be an implementation detail. For - * instance, an implementation could maintain a registry of all trusted objects by context. In - * such a case, trustAs() would return the same object that was passed in. getTrusted() would - * return the same object passed in if it was found in the registry under a compatible context or - * throw an exception otherwise. An implementation might only wrap values some of the time based - * on some criteria. getTrusted() might return a value and not throw an exception for special - * constants or objects even if not wrapped. All such implementations fulfill this contract. - * - * - * A note on the inheritance model for SCE contexts - * ------------------------------------------------ - * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This - * is purely an implementation details. - * - * The contract is simply this: - * - * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) - * will also succeed. - * - * Inheritance happens to capture this in a natural way. In some future, we - * may not use inheritance anymore. That is OK because no code outside of - * sce.js and sceSpecs.js would need to be aware of this detail. - */ - - this.$get = ['$parse', '$sniffer', '$sceDelegate', function( - $parse, $sniffer, $sceDelegate) { - // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows - // the "expression(javascript expression)" syntax which is insecure. - if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) { - throw $sceMinErr('iequirks', - 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' + - 'mode. You can fix this by adding the text to the top of your HTML ' + - 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); - } - - var sce = shallowCopy(SCE_CONTEXTS); - - /** - * @ngdoc method - * @name $sce#isEnabled - * @kind function - * - * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you - * have to do it at module config time on {@link ng.$sceProvider $sceProvider}. - * - * @description - * Returns a boolean indicating if SCE is enabled. - */ - sce.isEnabled = function () { - return enabled; - }; - sce.trustAs = $sceDelegate.trustAs; - sce.getTrusted = $sceDelegate.getTrusted; - sce.valueOf = $sceDelegate.valueOf; - - if (!enabled) { - sce.trustAs = sce.getTrusted = function(type, value) { return value; }; - sce.valueOf = identity; - } - - /** - * @ngdoc method - * @name $sce#parseAs - * - * @description - * Converts Angular {@link guide/expression expression} into a function. This is like {@link - * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it - * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, - * *result*)} - * - * @param {string} type The kind of SCE context in which this result will be used. - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - sce.parseAs = function sceParseAs(type, expr) { - var parsed = $parse(expr); - if (parsed.literal && parsed.constant) { - return parsed; - } else { - return function sceParseAsTrusted(self, locals) { - return sce.getTrusted(type, parsed(self, locals)); - }; - } - }; - - /** - * @ngdoc method - * @name $sce#trustAs - * - * @description - * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, - * returns an object that is trusted by angular for use in specified strict contextual - * escaping contexts (such as ng-bind-html, ng-include, any src attribute - * interpolation, any dom event binding attribute interpolation such as for onclick, etc.) - * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual - * escaping. - * - * @param {string} type The kind of context in which this value is safe for use. e.g. url, - * resource_url, html, js and css. - * @param {*} value The value that that should be considered trusted/safe. - * @returns {*} A value that can be used to stand in for the provided `value` in places - * where Angular expects a $sce.trustAs() return value. - */ - - /** - * @ngdoc method - * @name $sce#trustAsHtml - * - * @description - * Shorthand method. `$sce.trustAsHtml(value)` → - * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} - * - * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml - * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives - * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#trustAs $sce.trustAs}.) - */ - - /** - * @ngdoc method - * @name $sce#trustAsUrl - * - * @description - * Shorthand method. `$sce.trustAsUrl(value)` → - * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} - * - * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl - * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives - * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#trustAs $sce.trustAs}.) - */ - - /** - * @ngdoc method - * @name $sce#trustAsResourceUrl - * - * @description - * Shorthand method. `$sce.trustAsResourceUrl(value)` → - * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} - * - * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl - * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives - * only accept expressions that are either literal constants or are the return - * value of {@link ng.$sce#trustAs $sce.trustAs}.) - */ - - /** - * @ngdoc method - * @name $sce#trustAsJs - * - * @description - * Shorthand method. `$sce.trustAsJs(value)` → - * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} - * - * @param {*} value The value to trustAs. - * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs - * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives - * only accept expressions that are either literal constants or are the - * return value of {@link ng.$sce#trustAs $sce.trustAs}.) - */ - - /** - * @ngdoc method - * @name $sce#getTrusted - * - * @description - * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, - * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the - * originally supplied value if the queried context type is a supertype of the created type. - * If this condition isn't satisfied, throws an exception. - * - * @param {string} type The kind of context in which this value is to be used. - * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} - * call. - * @returns {*} The value the was originally provided to - * {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context. - * Otherwise, throws an exception. - */ - - /** - * @ngdoc method - * @name $sce#getTrustedHtml - * - * @description - * Shorthand method. `$sce.getTrustedHtml(value)` → - * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} - * - * @param {*} value The value to pass to `$sce.getTrusted`. - * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` - */ - - /** - * @ngdoc method - * @name $sce#getTrustedCss - * - * @description - * Shorthand method. `$sce.getTrustedCss(value)` → - * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} - * - * @param {*} value The value to pass to `$sce.getTrusted`. - * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` - */ - - /** - * @ngdoc method - * @name $sce#getTrustedUrl - * - * @description - * Shorthand method. `$sce.getTrustedUrl(value)` → - * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} - * - * @param {*} value The value to pass to `$sce.getTrusted`. - * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` - */ - - /** - * @ngdoc method - * @name $sce#getTrustedResourceUrl - * - * @description - * Shorthand method. `$sce.getTrustedResourceUrl(value)` → - * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} - * - * @param {*} value The value to pass to `$sceDelegate.getTrusted`. - * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` - */ - - /** - * @ngdoc method - * @name $sce#getTrustedJs - * - * @description - * Shorthand method. `$sce.getTrustedJs(value)` → - * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} - * - * @param {*} value The value to pass to `$sce.getTrusted`. - * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` - */ - - /** - * @ngdoc method - * @name $sce#parseAsHtml - * - * @description - * Shorthand method. `$sce.parseAsHtml(expression string)` → - * {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`} - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - - /** - * @ngdoc method - * @name $sce#parseAsCss - * - * @description - * Shorthand method. `$sce.parseAsCss(value)` → - * {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`} - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - - /** - * @ngdoc method - * @name $sce#parseAsUrl - * - * @description - * Shorthand method. `$sce.parseAsUrl(value)` → - * {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`} - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - - /** - * @ngdoc method - * @name $sce#parseAsResourceUrl - * - * @description - * Shorthand method. `$sce.parseAsResourceUrl(value)` → - * {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`} - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - - /** - * @ngdoc method - * @name $sce#parseAsJs - * - * @description - * Shorthand method. `$sce.parseAsJs(value)` → - * {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`} - * - * @param {string} expression String expression to compile. - * @returns {function(context, locals)} a function which represents the compiled expression: - * - * * `context` – `{object}` – an object against which any expressions embedded in the strings - * are evaluated against (typically a scope object). - * * `locals` – `{object=}` – local variables context object, useful for overriding values in - * `context`. - */ - - // Shorthand delegations. - var parse = sce.parseAs, - getTrusted = sce.getTrusted, - trustAs = sce.trustAs; - - forEach(SCE_CONTEXTS, function (enumValue, name) { - var lName = lowercase(name); - sce[camelCase("parse_as_" + lName)] = function (expr) { - return parse(enumValue, expr); - }; - sce[camelCase("get_trusted_" + lName)] = function (value) { - return getTrusted(enumValue, value); - }; - sce[camelCase("trust_as_" + lName)] = function (value) { - return trustAs(enumValue, value); - }; - }); - - return sce; - }]; -} - -/** - * !!! This is an undocumented "private" service !!! - * - * @name $sniffer - * @requires $window - * @requires $document - * - * @property {boolean} history Does the browser support html5 history api ? - * @property {boolean} hashchange Does the browser support hashchange event ? - * @property {boolean} transitions Does the browser support CSS transition events ? - * @property {boolean} animations Does the browser support CSS animation events ? - * - * @description - * This is very simple implementation of testing browser's features. - */ -function $SnifferProvider() { - this.$get = ['$window', '$document', function($window, $document) { - var eventSupport = {}, - android = - int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), - boxee = /Boxee/i.test(($window.navigator || {}).userAgent), - document = $document[0] || {}, - documentMode = document.documentMode, - vendorPrefix, - vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/, - bodyStyle = document.body && document.body.style, - transitions = false, - animations = false, - match; - - if (bodyStyle) { - for(var prop in bodyStyle) { - if(match = vendorRegex.exec(prop)) { - vendorPrefix = match[0]; - vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1); - break; - } - } - - if(!vendorPrefix) { - vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit'; - } - - transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle)); - animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle)); - - if (android && (!transitions||!animations)) { - transitions = isString(document.body.style.webkitTransition); - animations = isString(document.body.style.webkitAnimation); - } - } - - - return { - // Android has history.pushState, but it does not update location correctly - // so let's not use the history API at all. - // http://code.google.com/p/android/issues/detail?id=17471 - // https://github.com/angular/angular.js/issues/904 - - // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has - // so let's not use the history API also - // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined - // jshint -W018 - history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee), - // jshint +W018 - hashchange: 'onhashchange' in $window && - // IE8 compatible mode lies - (!documentMode || documentMode > 7), - hasEvent: function(event) { - // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have - // it. In particular the event is not fired when backspace or delete key are pressed or - // when cut operation is performed. - if (event == 'input' && msie == 9) return false; - - if (isUndefined(eventSupport[event])) { - var divElm = document.createElement('div'); - eventSupport[event] = 'on' + event in divElm; - } - - return eventSupport[event]; - }, - csp: csp(), - vendorPrefix: vendorPrefix, - transitions : transitions, - animations : animations, - android: android, - msie : msie, - msieDocumentMode: documentMode - }; - }]; -} - -function $TimeoutProvider() { - this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler', - function($rootScope, $browser, $q, $exceptionHandler) { - var deferreds = {}; - - - /** - * @ngdoc service - * @name $timeout - * - * @description - * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch - * block and delegates any exceptions to - * {@link ng.$exceptionHandler $exceptionHandler} service. - * - * The return value of registering a timeout function is a promise, which will be resolved when - * the timeout is reached and the timeout function is executed. - * - * To cancel a timeout request, call `$timeout.cancel(promise)`. - * - * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to - * synchronously flush the queue of deferred functions. - * - * @param {function()} fn A function, whose execution should be delayed. - * @param {number=} [delay=0] Delay in milliseconds. - * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise - * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. - * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this - * promise will be resolved with is the return value of the `fn` function. - * - */ - function timeout(fn, delay, invokeApply) { - var deferred = $q.defer(), - promise = deferred.promise, - skipApply = (isDefined(invokeApply) && !invokeApply), - timeoutId; - - timeoutId = $browser.defer(function() { - try { - deferred.resolve(fn()); - } catch(e) { - deferred.reject(e); - $exceptionHandler(e); - } - finally { - delete deferreds[promise.$$timeoutId]; - } - - if (!skipApply) $rootScope.$apply(); - }, delay); - - promise.$$timeoutId = timeoutId; - deferreds[timeoutId] = deferred; - - return promise; - } - - - /** - * @ngdoc method - * @name $timeout#cancel - * - * @description - * Cancels a task associated with the `promise`. As a result of this, the promise will be - * resolved with a rejection. - * - * @param {Promise=} promise Promise returned by the `$timeout` function. - * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully - * canceled. - */ - timeout.cancel = function(promise) { - if (promise && promise.$$timeoutId in deferreds) { - deferreds[promise.$$timeoutId].reject('canceled'); - delete deferreds[promise.$$timeoutId]; - return $browser.defer.cancel(promise.$$timeoutId); - } - return false; - }; - - return timeout; - }]; -} - -// NOTE: The usage of window and document instead of $window and $document here is -// deliberate. This service depends on the specific behavior of anchor nodes created by the -// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and -// cause us to break tests. In addition, when the browser resolves a URL for XHR, it -// doesn't know about mocked locations and resolves URLs to the real document - which is -// exactly the behavior needed here. There is little value is mocking these out for this -// service. -var urlParsingNode = document.createElement("a"); -var originUrl = urlResolve(window.location.href, true); - - -/** - * - * Implementation Notes for non-IE browsers - * ---------------------------------------- - * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, - * results both in the normalizing and parsing of the URL. Normalizing means that a relative - * URL will be resolved into an absolute URL in the context of the application document. - * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related - * properties are all populated to reflect the normalized URL. This approach has wide - * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See - * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html - * - * Implementation Notes for IE - * --------------------------- - * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other - * browsers. However, the parsed components will not be set if the URL assigned did not specify - * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We - * work around that by performing the parsing in a 2nd step by taking a previously normalized - * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the - * properties such as protocol, hostname, port, etc. - * - * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one - * uses the inner HTML approach to assign the URL as part of an HTML snippet - - * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL. - * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception. - * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that - * method and IE < 8 is unsupported. - * - * References: - * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement - * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html - * http://url.spec.whatwg.org/#urlutils - * https://github.com/angular/angular.js/pull/2902 - * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ - * - * @kind function - * @param {string} url The URL to be parsed. - * @description Normalizes and parses a URL. - * @returns {object} Returns the normalized URL as a dictionary. - * - * | member name | Description | - * |---------------|----------------| - * | href | A normalized version of the provided URL if it was not an absolute URL | - * | protocol | The protocol including the trailing colon | - * | host | The host and port (if the port is non-default) of the normalizedUrl | - * | search | The search params, minus the question mark | - * | hash | The hash string, minus the hash symbol - * | hostname | The hostname - * | port | The port, without ":" - * | pathname | The pathname, beginning with "/" - * - */ -function urlResolve(url, base) { - var href = url; - - if (msie) { - // Normalize before parse. Refer Implementation Notes on why this is - // done in two steps on IE. - urlParsingNode.setAttribute("href", href); - href = urlParsingNode.href; - } - - urlParsingNode.setAttribute('href', href); - - // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils - return { - href: urlParsingNode.href, - protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', - host: urlParsingNode.host, - search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', - hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', - hostname: urlParsingNode.hostname, - port: urlParsingNode.port, - pathname: (urlParsingNode.pathname.charAt(0) === '/') - ? urlParsingNode.pathname - : '/' + urlParsingNode.pathname - }; -} - -/** - * Parse a request URL and determine whether this is a same-origin request as the application document. - * - * @param {string|object} requestUrl The url of the request as a string that will be resolved - * or a parsed URL object. - * @returns {boolean} Whether the request is for the same origin as the application document. - */ -function urlIsSameOrigin(requestUrl) { - var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; - return (parsed.protocol === originUrl.protocol && - parsed.host === originUrl.host); -} - -/** - * @ngdoc service - * @name $window - * - * @description - * A reference to the browser's `window` object. While `window` - * is globally available in JavaScript, it causes testability problems, because - * it is a global variable. In angular we always refer to it through the - * `$window` service, so it may be overridden, removed or mocked for testing. - * - * Expressions, like the one defined for the `ngClick` directive in the example - * below, are evaluated with respect to the current scope. Therefore, there is - * no risk of inadvertently coding in a dependency on a global value in such an - * expression. - * - * @example - - - -
- - -
-
- - it('should display the greeting in the input box', function() { - element(by.model('greeting')).sendKeys('Hello, E2E Tests'); - // If we click the button it will block the test runner - // element(':button').click(); - }); - -
- */ -function $WindowProvider(){ - this.$get = valueFn(window); -} - -/* global currencyFilter: true, - dateFilter: true, - filterFilter: true, - jsonFilter: true, - limitToFilter: true, - lowercaseFilter: true, - numberFilter: true, - orderByFilter: true, - uppercaseFilter: true, - */ - -/** - * @ngdoc provider - * @name $filterProvider - * @description - * - * Filters are just functions which transform input to an output. However filters need to be - * Dependency Injected. To achieve this a filter definition consists of a factory function which is - * annotated with dependencies and is responsible for creating a filter function. - * - * ```js - * // Filter registration - * function MyModule($provide, $filterProvider) { - * // create a service to demonstrate injection (not always needed) - * $provide.value('greet', function(name){ - * return 'Hello ' + name + '!'; - * }); - * - * // register a filter factory which uses the - * // greet service to demonstrate DI. - * $filterProvider.register('greet', function(greet){ - * // return the filter function which uses the greet service - * // to generate salutation - * return function(text) { - * // filters need to be forgiving so check input validity - * return text && greet(text) || text; - * }; - * }); - * } - * ``` - * - * The filter function is registered with the `$injector` under the filter name suffix with - * `Filter`. - * - * ```js - * it('should be the same instance', inject( - * function($filterProvider) { - * $filterProvider.register('reverse', function(){ - * return ...; - * }); - * }, - * function($filter, reverseFilter) { - * expect($filter('reverse')).toBe(reverseFilter); - * }); - * ``` - * - * - * For more information about how angular filters work, and how to create your own filters, see - * {@link guide/filter Filters} in the Angular Developer Guide. - */ - -/** - * @ngdoc service - * @name $filter - * @kind function - * @description - * Filters are used for formatting data displayed to the user. - * - * The general syntax in templates is as follows: - * - * {{ expression [| filter_name[:parameter_value] ... ] }} - * - * @param {String} name Name of the filter function to retrieve - * @return {Function} the filter function - * @example - - -
-

{{ originalText }}

-

{{ filteredText }}

-
-
- - - angular.module('filterExample', []) - .controller('MainCtrl', function($scope, $filter) { - $scope.originalText = 'hello'; - $scope.filteredText = $filter('uppercase')($scope.originalText); - }); - -
- */ -$FilterProvider.$inject = ['$provide']; -function $FilterProvider($provide) { - var suffix = 'Filter'; - - /** - * @ngdoc method - * @name $filterProvider#register - * @param {string|Object} name Name of the filter function, or an object map of filters where - * the keys are the filter names and the values are the filter factories. - * @returns {Object} Registered filter instance, or if a map of filters was provided then a map - * of the registered filter instances. - */ - function register(name, factory) { - if(isObject(name)) { - var filters = {}; - forEach(name, function(filter, key) { - filters[key] = register(key, filter); - }); - return filters; - } else { - return $provide.factory(name + suffix, factory); - } - } - this.register = register; - - this.$get = ['$injector', function($injector) { - return function(name) { - return $injector.get(name + suffix); - }; - }]; - - //////////////////////////////////////// - - /* global - currencyFilter: false, - dateFilter: false, - filterFilter: false, - jsonFilter: false, - limitToFilter: false, - lowercaseFilter: false, - numberFilter: false, - orderByFilter: false, - uppercaseFilter: false, - */ - - register('currency', currencyFilter); - register('date', dateFilter); - register('filter', filterFilter); - register('json', jsonFilter); - register('limitTo', limitToFilter); - register('lowercase', lowercaseFilter); - register('number', numberFilter); - register('orderBy', orderByFilter); - register('uppercase', uppercaseFilter); -} - -/** - * @ngdoc filter - * @name filter - * @kind function - * - * @description - * Selects a subset of items from `array` and returns it as a new array. - * - * @param {Array} array The source array. - * @param {string|Object|function()} expression The predicate to be used for selecting items from - * `array`. - * - * Can be one of: - * - * - `string`: The string is evaluated as an expression and the resulting value is used for substring match against - * the contents of the `array`. All strings or objects with string properties in `array` that contain this string - * will be returned. The predicate can be negated by prefixing the string with `!`. - * - * - `Object`: A pattern object can be used to filter specific properties on objects contained - * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items - * which have property `name` containing "M" and property `phone` containing "1". A special - * property name `$` can be used (as in `{$:"text"}`) to accept a match against any - * property of the object. That's equivalent to the simple substring match with a `string` - * as described above. The predicate can be negated by prefixing the string with `!`. - * For Example `{name: "!M"}` predicate will return an array of items which have property `name` - * not containing "M". - * - * - `function(value)`: A predicate function can be used to write arbitrary filters. The function is - * called for each element of `array`. The final result is an array of those elements that - * the predicate returned true for. - * - * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in - * determining if the expected value (from the filter expression) and actual value (from - * the object in the array) should be considered a match. - * - * Can be one of: - * - * - `function(actual, expected)`: - * The function will be given the object value and the predicate value to compare and - * should return true if the item should be included in filtered result. - * - * - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`. - * this is essentially strict comparison of expected and actual. - * - * - `false|undefined`: A short hand for a function which will look for a substring match in case - * insensitive way. - * - * @example - - -
- - Search: - - - - - - -
NamePhone
{{friend.name}}{{friend.phone}}
-
- Any:
- Name only
- Phone only
- Equality
- - - - - - -
NamePhone
{{friendObj.name}}{{friendObj.phone}}
-
- - var expectFriendNames = function(expectedNames, key) { - element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) { - arr.forEach(function(wd, i) { - expect(wd.getText()).toMatch(expectedNames[i]); - }); - }); - }; - - it('should search across all fields when filtering with a string', function() { - var searchText = element(by.model('searchText')); - searchText.clear(); - searchText.sendKeys('m'); - expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend'); - - searchText.clear(); - searchText.sendKeys('76'); - expectFriendNames(['John', 'Julie'], 'friend'); - }); - - it('should search in specific fields when filtering with a predicate object', function() { - var searchAny = element(by.model('search.$')); - searchAny.clear(); - searchAny.sendKeys('i'); - expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj'); - }); - it('should use a equal comparison when comparator is true', function() { - var searchName = element(by.model('search.name')); - var strict = element(by.model('strict')); - searchName.clear(); - searchName.sendKeys('Julie'); - strict.click(); - expectFriendNames(['Julie'], 'friendObj'); - }); - -
- */ -function filterFilter() { - return function(array, expression, comparator) { - if (!isArray(array)) return array; - - var comparatorType = typeof(comparator), - predicates = []; - - predicates.check = function(value) { - for (var j = 0; j < predicates.length; j++) { - if(!predicates[j](value)) { - return false; - } - } - return true; - }; - - if (comparatorType !== 'function') { - if (comparatorType === 'boolean' && comparator) { - comparator = function(obj, text) { - return angular.equals(obj, text); - }; - } else { - comparator = function(obj, text) { - if (obj && text && typeof obj === 'object' && typeof text === 'object') { - for (var objKey in obj) { - if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) && - comparator(obj[objKey], text[objKey])) { - return true; - } - } - return false; - } - text = (''+text).toLowerCase(); - return (''+obj).toLowerCase().indexOf(text) > -1; - }; - } - } - - var search = function(obj, text){ - if (typeof text === 'string' && text.charAt(0) === '!') { - return !search(obj, text.substr(1)); - } - switch (typeof obj) { - case 'boolean': - case 'number': - case 'string': - return comparator(obj, text); - case 'object': - switch (typeof text) { - case 'object': - return comparator(obj, text); - default: - for ( var objKey in obj) { - if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { - return true; - } - } - break; - } - return false; - case 'array': - for ( var i = 0; i < obj.length; i++) { - if (search(obj[i], text)) { - return true; - } - } - return false; - default: - return false; - } - }; - switch (typeof expression) { - case 'boolean': - case 'number': - case 'string': - // Set up expression object and fall through - expression = {$:expression}; - // jshint -W086 - case 'object': - // jshint +W086 - for (var key in expression) { - (function(path) { - if (typeof expression[path] === 'undefined') return; - predicates.push(function(value) { - return search(path == '$' ? value : (value && value[path]), expression[path]); - }); - })(key); - } - break; - case 'function': - predicates.push(expression); - break; - default: - return array; - } - var filtered = []; - for ( var j = 0; j < array.length; j++) { - var value = array[j]; - if (predicates.check(value)) { - filtered.push(value); - } - } - return filtered; - }; -} - -/** - * @ngdoc filter - * @name currency - * @kind function - * - * @description - * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default - * symbol for current locale is used. - * - * @param {number} amount Input to filter. - * @param {string=} symbol Currency symbol or identifier to be displayed. - * @returns {string} Formatted number. - * - * - * @example - - - -
-
- default currency symbol ($): {{amount | currency}}
- custom currency identifier (USD$): {{amount | currency:"USD$"}} -
-
- - it('should init with 1234.56', function() { - expect(element(by.id('currency-default')).getText()).toBe('$1,234.56'); - expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56'); - }); - it('should update', function() { - if (browser.params.browser == 'safari') { - // Safari does not understand the minus key. See - // https://github.com/angular/protractor/issues/481 - return; - } - element(by.model('amount')).clear(); - element(by.model('amount')).sendKeys('-1234'); - expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)'); - expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)'); - }); - -
- */ -currencyFilter.$inject = ['$locale']; -function currencyFilter($locale) { - var formats = $locale.NUMBER_FORMATS; - return function(amount, currencySymbol){ - if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM; - return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2). - replace(/\u00A4/g, currencySymbol); - }; -} - -/** - * @ngdoc filter - * @name number - * @kind function - * - * @description - * Formats a number as text. - * - * If the input is not a number an empty string is returned. - * - * @param {number|string} number Number to format. - * @param {(number|string)=} fractionSize Number of decimal places to round the number to. - * If this is not provided then the fraction size is computed from the current locale's number - * formatting pattern. In the case of the default locale, it will be 3. - * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. - * - * @example - - - -
- Enter number:
- Default formatting: {{val | number}}
- No fractions: {{val | number:0}}
- Negative number: {{-val | number:4}} -
-
- - it('should format numbers', function() { - expect(element(by.id('number-default')).getText()).toBe('1,234.568'); - expect(element(by.binding('val | number:0')).getText()).toBe('1,235'); - expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679'); - }); - - it('should update', function() { - element(by.model('val')).clear(); - element(by.model('val')).sendKeys('3374.333'); - expect(element(by.id('number-default')).getText()).toBe('3,374.333'); - expect(element(by.binding('val | number:0')).getText()).toBe('3,374'); - expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330'); - }); - -
- */ - - -numberFilter.$inject = ['$locale']; -function numberFilter($locale) { - var formats = $locale.NUMBER_FORMATS; - return function(number, fractionSize) { - return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, - fractionSize); - }; -} - -var DECIMAL_SEP = '.'; -function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { - if (number == null || !isFinite(number) || isObject(number)) return ''; - - var isNegative = number < 0; - number = Math.abs(number); - var numStr = number + '', - formatedText = '', - parts = []; - - var hasExponent = false; - if (numStr.indexOf('e') !== -1) { - var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); - if (match && match[2] == '-' && match[3] > fractionSize + 1) { - numStr = '0'; - number = 0; - } else { - formatedText = numStr; - hasExponent = true; - } - } - - if (!hasExponent) { - var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length; - - // determine fractionSize if it is not specified - if (isUndefined(fractionSize)) { - fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac); - } - - // safely round numbers in JS without hitting imprecisions of floating-point arithmetics - // inspired by: - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round - number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize); - - if (number === 0) { - isNegative = false; - } - - var fraction = ('' + number).split(DECIMAL_SEP); - var whole = fraction[0]; - fraction = fraction[1] || ''; - - var i, pos = 0, - lgroup = pattern.lgSize, - group = pattern.gSize; - - if (whole.length >= (lgroup + group)) { - pos = whole.length - lgroup; - for (i = 0; i < pos; i++) { - if ((pos - i)%group === 0 && i !== 0) { - formatedText += groupSep; - } - formatedText += whole.charAt(i); - } - } - - for (i = pos; i < whole.length; i++) { - if ((whole.length - i)%lgroup === 0 && i !== 0) { - formatedText += groupSep; - } - formatedText += whole.charAt(i); - } - - // format fraction part. - while(fraction.length < fractionSize) { - fraction += '0'; - } - - if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize); - } else { - - if (fractionSize > 0 && number > -1 && number < 1) { - formatedText = number.toFixed(fractionSize); - } - } - - parts.push(isNegative ? pattern.negPre : pattern.posPre); - parts.push(formatedText); - parts.push(isNegative ? pattern.negSuf : pattern.posSuf); - return parts.join(''); -} - -function padNumber(num, digits, trim) { - var neg = ''; - if (num < 0) { - neg = '-'; - num = -num; - } - num = '' + num; - while(num.length < digits) num = '0' + num; - if (trim) - num = num.substr(num.length - digits); - return neg + num; -} - - -function dateGetter(name, size, offset, trim) { - offset = offset || 0; - return function(date) { - var value = date['get' + name](); - if (offset > 0 || value > -offset) - value += offset; - if (value === 0 && offset == -12 ) value = 12; - return padNumber(value, size, trim); - }; -} - -function dateStrGetter(name, shortForm) { - return function(date, formats) { - var value = date['get' + name](); - var get = uppercase(shortForm ? ('SHORT' + name) : name); - - return formats[get][value]; - }; -} - -function timeZoneGetter(date) { - var zone = -1 * date.getTimezoneOffset(); - var paddedZone = (zone >= 0) ? "+" : ""; - - paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + - padNumber(Math.abs(zone % 60), 2); - - return paddedZone; -} - -function ampmGetter(date, formats) { - return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]; -} - -var DATE_FORMATS = { - yyyy: dateGetter('FullYear', 4), - yy: dateGetter('FullYear', 2, 0, true), - y: dateGetter('FullYear', 1), - MMMM: dateStrGetter('Month'), - MMM: dateStrGetter('Month', true), - MM: dateGetter('Month', 2, 1), - M: dateGetter('Month', 1, 1), - dd: dateGetter('Date', 2), - d: dateGetter('Date', 1), - HH: dateGetter('Hours', 2), - H: dateGetter('Hours', 1), - hh: dateGetter('Hours', 2, -12), - h: dateGetter('Hours', 1, -12), - mm: dateGetter('Minutes', 2), - m: dateGetter('Minutes', 1), - ss: dateGetter('Seconds', 2), - s: dateGetter('Seconds', 1), - // while ISO 8601 requires fractions to be prefixed with `.` or `,` - // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions - sss: dateGetter('Milliseconds', 3), - EEEE: dateStrGetter('Day'), - EEE: dateStrGetter('Day', true), - a: ampmGetter, - Z: timeZoneGetter -}; - -var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/, - NUMBER_STRING = /^\-?\d+$/; - -/** - * @ngdoc filter - * @name date - * @kind function - * - * @description - * Formats `date` to a string based on the requested `format`. - * - * `format` string can be composed of the following elements: - * - * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) - * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) - * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) - * * `'MMMM'`: Month in year (January-December) - * * `'MMM'`: Month in year (Jan-Dec) - * * `'MM'`: Month in year, padded (01-12) - * * `'M'`: Month in year (1-12) - * * `'dd'`: Day in month, padded (01-31) - * * `'d'`: Day in month (1-31) - * * `'EEEE'`: Day in Week,(Sunday-Saturday) - * * `'EEE'`: Day in Week, (Sun-Sat) - * * `'HH'`: Hour in day, padded (00-23) - * * `'H'`: Hour in day (0-23) - * * `'hh'`: Hour in am/pm, padded (01-12) - * * `'h'`: Hour in am/pm, (1-12) - * * `'mm'`: Minute in hour, padded (00-59) - * * `'m'`: Minute in hour (0-59) - * * `'ss'`: Second in minute, padded (00-59) - * * `'s'`: Second in minute (0-59) - * * `'.sss' or ',sss'`: Millisecond in second, padded (000-999) - * * `'a'`: am/pm marker - * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) - * - * `format` string can also be one of the following predefined - * {@link guide/i18n localizable formats}: - * - * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale - * (e.g. Sep 3, 2010 12:05:08 pm) - * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm) - * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale - * (e.g. Friday, September 3, 2010) - * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010) - * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010) - * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10) - * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm) - * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm) - * - * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g. - * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence - * (e.g. `"h 'o''clock'"`). - * - * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or - * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its - * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is - * specified in the string input, the time is considered to be in the local timezone. - * @param {string=} format Formatting rules (see Description). If not specified, - * `mediumDate` is used. - * @returns {string} Formatted string or the input if input is not recognized as date/millis. - * - * @example - - - {{1288323623006 | date:'medium'}}: - {{1288323623006 | date:'medium'}}
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}: - {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
- {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}: - {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
- {{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}: - {{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}
-
- - it('should format date', function() { - expect(element(by.binding("1288323623006 | date:'medium'")).getText()). - toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/); - expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()). - toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/); - expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()). - toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); - expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()). - toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/); - }); - -
- */ -dateFilter.$inject = ['$locale']; -function dateFilter($locale) { - - - var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; - // 1 2 3 4 5 6 7 8 9 10 11 - function jsonStringToDate(string) { - var match; - if (match = string.match(R_ISO8601_STR)) { - var date = new Date(0), - tzHour = 0, - tzMin = 0, - dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, - timeSetter = match[8] ? date.setUTCHours : date.setHours; - - if (match[9]) { - tzHour = int(match[9] + match[10]); - tzMin = int(match[9] + match[11]); - } - dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3])); - var h = int(match[4]||0) - tzHour; - var m = int(match[5]||0) - tzMin; - var s = int(match[6]||0); - var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000); - timeSetter.call(date, h, m, s, ms); - return date; - } - return string; - } - - - return function(date, format) { - var text = '', - parts = [], - fn, match; - - format = format || 'mediumDate'; - format = $locale.DATETIME_FORMATS[format] || format; - if (isString(date)) { - date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date); - } - - if (isNumber(date)) { - date = new Date(date); - } - - if (!isDate(date)) { - return date; - } - - while(format) { - match = DATE_FORMATS_SPLIT.exec(format); - if (match) { - parts = concat(parts, match, 1); - format = parts.pop(); - } else { - parts.push(format); - format = null; - } - } - - forEach(parts, function(value){ - fn = DATE_FORMATS[value]; - text += fn ? fn(date, $locale.DATETIME_FORMATS) - : value.replace(/(^'|'$)/g, '').replace(/''/g, "'"); - }); - - return text; - }; -} - - -/** - * @ngdoc filter - * @name json - * @kind function - * - * @description - * Allows you to convert a JavaScript object into JSON string. - * - * This filter is mostly useful for debugging. When using the double curly {{value}} notation - * the binding is automatically converted to JSON. - * - * @param {*} object Any JavaScript object (including arrays and primitive types) to filter. - * @returns {string} JSON string. - * - * - * @example - - -
{{ {'name':'value'} | json }}
-
- - it('should jsonify filtered objects', function() { - expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/); - }); - -
- * - */ -function jsonFilter() { - return function(object) { - return toJson(object, true); - }; -} - - -/** - * @ngdoc filter - * @name lowercase - * @kind function - * @description - * Converts string to lowercase. - * @see angular.lowercase - */ -var lowercaseFilter = valueFn(lowercase); - - -/** - * @ngdoc filter - * @name uppercase - * @kind function - * @description - * Converts string to uppercase. - * @see angular.uppercase - */ -var uppercaseFilter = valueFn(uppercase); - -/** - * @ngdoc filter - * @name limitTo - * @kind function - * - * @description - * Creates a new array or string containing only a specified number of elements. The elements - * are taken from either the beginning or the end of the source array or string, as specified by - * the value and sign (positive or negative) of `limit`. - * - * @param {Array|string} input Source array or string to be limited. - * @param {string|number} limit The length of the returned array or string. If the `limit` number - * is positive, `limit` number of items from the beginning of the source array/string are copied. - * If the number is negative, `limit` number of items from the end of the source array/string - * are copied. The `limit` will be trimmed if it exceeds `array.length` - * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array - * had less than `limit` elements. - * - * @example - - - -
- Limit {{numbers}} to: -

Output numbers: {{ numbers | limitTo:numLimit }}

- Limit {{letters}} to: -

Output letters: {{ letters | limitTo:letterLimit }}

-
-
- - var numLimitInput = element(by.model('numLimit')); - var letterLimitInput = element(by.model('letterLimit')); - var limitedNumbers = element(by.binding('numbers | limitTo:numLimit')); - var limitedLetters = element(by.binding('letters | limitTo:letterLimit')); - - it('should limit the number array to first three items', function() { - expect(numLimitInput.getAttribute('value')).toBe('3'); - expect(letterLimitInput.getAttribute('value')).toBe('3'); - expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]'); - expect(limitedLetters.getText()).toEqual('Output letters: abc'); - }); - - // There is a bug in safari and protractor that doesn't like the minus key - // it('should update the output when -3 is entered', function() { - // numLimitInput.clear(); - // numLimitInput.sendKeys('-3'); - // letterLimitInput.clear(); - // letterLimitInput.sendKeys('-3'); - // expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]'); - // expect(limitedLetters.getText()).toEqual('Output letters: ghi'); - // }); - - it('should not exceed the maximum size of input array', function() { - numLimitInput.clear(); - numLimitInput.sendKeys('100'); - letterLimitInput.clear(); - letterLimitInput.sendKeys('100'); - expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]'); - expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi'); - }); - -
- */ -function limitToFilter(){ - return function(input, limit) { - if (!isArray(input) && !isString(input)) return input; - - if (Math.abs(Number(limit)) === Infinity) { - limit = Number(limit); - } else { - limit = int(limit); - } - - if (isString(input)) { - //NaN check on limit - if (limit) { - return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length); - } else { - return ""; - } - } - - var out = [], - i, n; - - // if abs(limit) exceeds maximum length, trim it - if (limit > input.length) - limit = input.length; - else if (limit < -input.length) - limit = -input.length; - - if (limit > 0) { - i = 0; - n = limit; - } else { - i = input.length + limit; - n = input.length; - } - - for (; i=} expression A predicate to be - * used by the comparator to determine the order of elements. - * - * Can be one of: - * - * - `function`: Getter function. The result of this function will be sorted using the - * `<`, `=`, `>` operator. - * - `string`: An Angular expression. The result of this expression is used to compare elements - * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by - * 3 first characters of a property called `name`). The result of a constant expression - * is interpreted as a property name to be used in comparisons (for example `"special name"` - * to sort object by the value of their `special name` property). An expression can be - * optionally prefixed with `+` or `-` to control ascending or descending sort order - * (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array - * element itself is used to compare where sorting. - * - `Array`: An array of function or string predicates. The first predicate in the array - * is used for sorting, but when two items are equivalent, the next predicate is used. - * - * If the predicate is missing or empty then it defaults to `'+'`. - * - * @param {boolean=} reverse Reverse the order of the array. - * @returns {Array} Sorted copy of the source array. - * - * @example - - - -
-
Sorting predicate = {{predicate}}; reverse = {{reverse}}
-
- [ unsorted ] - - - - - - - - - - - -
Name - (^)Phone NumberAge
{{friend.name}}{{friend.phone}}{{friend.age}}
-
-
-
- * - * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the - * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the - * desired parameters. - * - * Example: - * - * @example - - -
- - - - - - - - - - - -
Name - (^)Phone NumberAge
{{friend.name}}{{friend.phone}}{{friend.age}}
-
-
- - - angular.module('orderByExample', []) - .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) { - var orderBy = $filter('orderBy'); - $scope.friends = [ - { name: 'John', phone: '555-1212', age: 10 }, - { name: 'Mary', phone: '555-9876', age: 19 }, - { name: 'Mike', phone: '555-4321', age: 21 }, - { name: 'Adam', phone: '555-5678', age: 35 }, - { name: 'Julie', phone: '555-8765', age: 29 } - ]; - $scope.order = function(predicate, reverse) { - $scope.friends = orderBy($scope.friends, predicate, reverse); - }; - $scope.order('-age',false); - }]); - -
- */ -orderByFilter.$inject = ['$parse']; -function orderByFilter($parse){ - return function(array, sortPredicate, reverseOrder) { - if (!(isArrayLike(array))) return array; - sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate]; - if (sortPredicate.length === 0) { sortPredicate = ['+']; } - sortPredicate = map(sortPredicate, function(predicate){ - var descending = false, get = predicate || identity; - if (isString(predicate)) { - if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) { - descending = predicate.charAt(0) == '-'; - predicate = predicate.substring(1); - } - if ( predicate === '' ) { - // Effectively no predicate was passed so we compare identity - return reverseComparator(function(a,b) { - return compare(a, b); - }, descending); - } - get = $parse(predicate); - if (get.constant) { - var key = get(); - return reverseComparator(function(a,b) { - return compare(a[key], b[key]); - }, descending); - } - } - return reverseComparator(function(a,b){ - return compare(get(a),get(b)); - }, descending); - }); - return slice.call(array).sort(reverseComparator(comparator, reverseOrder)); - - function comparator(o1, o2){ - for ( var i = 0; i < sortPredicate.length; i++) { - var comp = sortPredicate[i](o1, o2); - if (comp !== 0) return comp; - } - return 0; - } - function reverseComparator(comp, descending) { - return toBoolean(descending) - ? function(a,b){return comp(b,a);} - : comp; - } - function compare(v1, v2){ - var t1 = typeof v1; - var t2 = typeof v2; - if (t1 == t2) { - if (isDate(v1) && isDate(v2)) { - v1 = v1.valueOf(); - v2 = v2.valueOf(); - } - if (t1 == "string") { - v1 = v1.toLowerCase(); - v2 = v2.toLowerCase(); - } - if (v1 === v2) return 0; - return v1 < v2 ? -1 : 1; - } else { - return t1 < t2 ? -1 : 1; - } - } - }; -} - -function ngDirective(directive) { - if (isFunction(directive)) { - directive = { - link: directive - }; - } - directive.restrict = directive.restrict || 'AC'; - return valueFn(directive); -} - -/** - * @ngdoc directive - * @name a - * @restrict E - * - * @description - * Modifies the default behavior of the html A tag so that the default action is prevented when - * the href attribute is empty. - * - * This change permits the easy creation of action links with the `ngClick` directive - * without changing the location or causing page reloads, e.g.: - * `Add Item` - */ -var htmlAnchorDirective = valueFn({ - restrict: 'E', - compile: function(element, attr) { - - if (msie <= 8) { - - // turn link into a stylable link in IE - // but only if it doesn't have name attribute, in which case it's an anchor - if (!attr.href && !attr.name) { - attr.$set('href', ''); - } - - // add a comment node to anchors to workaround IE bug that causes element content to be reset - // to new attribute content if attribute is updated with value containing @ and element also - // contains value with @ - // see issue #1949 - element.append(document.createComment('IE fix')); - } - - if (!attr.href && !attr.xlinkHref && !attr.name) { - return function(scope, element) { - // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. - var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? - 'xlink:href' : 'href'; - element.on('click', function(event){ - // if we have no href url, then don't navigate anywhere. - if (!element.attr(href)) { - event.preventDefault(); - } - }); - }; - } - } -}); - -/** - * @ngdoc directive - * @name ngHref - * @restrict A - * @priority 99 - * - * @description - * Using Angular markup like `{{hash}}` in an href attribute will - * make the link go to the wrong URL if the user clicks it before - * Angular has a chance to replace the `{{hash}}` markup with its - * value. Until Angular replaces the markup the link will be broken - * and will most likely return a 404 error. The `ngHref` directive - * solves this problem. - * - * The wrong way to write it: - * ```html - * - * ``` - * - * The correct way to write it: - * ```html - * - * ``` - * - * @element A - * @param {template} ngHref any string which can contain `{{}}` markup. - * - * @example - * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes - * in links and their different behaviors: - - -
-
link 1 (link, don't reload)
- link 2 (link, don't reload)
- link 3 (link, reload!)
- anchor (link, don't reload)
- anchor (no link)
- link (link, change location) -
- - it('should execute ng-click but not reload when href without value', function() { - element(by.id('link-1')).click(); - expect(element(by.model('value')).getAttribute('value')).toEqual('1'); - expect(element(by.id('link-1')).getAttribute('href')).toBe(''); - }); - - it('should execute ng-click but not reload when href empty string', function() { - element(by.id('link-2')).click(); - expect(element(by.model('value')).getAttribute('value')).toEqual('2'); - expect(element(by.id('link-2')).getAttribute('href')).toBe(''); - }); - - it('should execute ng-click and change url when ng-href specified', function() { - expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/); - - element(by.id('link-3')).click(); - - // At this point, we navigate away from an Angular page, so we need - // to use browser.driver to get the base webdriver. - - browser.wait(function() { - return browser.driver.getCurrentUrl().then(function(url) { - return url.match(/\/123$/); - }); - }, 5000, 'page should navigate to /123'); - }); - - xit('should execute ng-click but not reload when href empty string and name specified', function() { - element(by.id('link-4')).click(); - expect(element(by.model('value')).getAttribute('value')).toEqual('4'); - expect(element(by.id('link-4')).getAttribute('href')).toBe(''); - }); - - it('should execute ng-click but not reload when no href but name specified', function() { - element(by.id('link-5')).click(); - expect(element(by.model('value')).getAttribute('value')).toEqual('5'); - expect(element(by.id('link-5')).getAttribute('href')).toBe(null); - }); - - it('should only change url when only ng-href', function() { - element(by.model('value')).clear(); - element(by.model('value')).sendKeys('6'); - expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/); - - element(by.id('link-6')).click(); - - // At this point, we navigate away from an Angular page, so we need - // to use browser.driver to get the base webdriver. - browser.wait(function() { - return browser.driver.getCurrentUrl().then(function(url) { - return url.match(/\/6$/); - }); - }, 5000, 'page should navigate to /6'); - }); - - - */ - -/** - * @ngdoc directive - * @name ngSrc - * @restrict A - * @priority 99 - * - * @description - * Using Angular markup like `{{hash}}` in a `src` attribute doesn't - * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside - * `{{hash}}`. The `ngSrc` directive solves this problem. - * - * The buggy way to write it: - * ```html - * - * ``` - * - * The correct way to write it: - * ```html - * - * ``` - * - * @element IMG - * @param {template} ngSrc any string which can contain `{{}}` markup. - */ - -/** - * @ngdoc directive - * @name ngSrcset - * @restrict A - * @priority 99 - * - * @description - * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't - * work right: The browser will fetch from the URL with the literal - * text `{{hash}}` until Angular replaces the expression inside - * `{{hash}}`. The `ngSrcset` directive solves this problem. - * - * The buggy way to write it: - * ```html - * - * ``` - * - * The correct way to write it: - * ```html - * - * ``` - * - * @element IMG - * @param {template} ngSrcset any string which can contain `{{}}` markup. - */ - -/** - * @ngdoc directive - * @name ngDisabled - * @restrict A - * @priority 100 - * - * @description - * - * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: - * ```html - *
- * - *
- * ``` - * - * The HTML specification does not require browsers to preserve the values of boolean attributes - * such as disabled. (Their presence means true and their absence means false.) - * If we put an Angular interpolation expression into such an attribute then the - * binding information would be lost when the browser removes the attribute. - * The `ngDisabled` directive solves this problem for the `disabled` attribute. - * This complementary directive is not removed by the browser and so provides - * a permanent reliable place to store the binding information. - * - * @example - - - Click me to toggle:
- -
- - it('should toggle button', function() { - expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy(); - element(by.model('checked')).click(); - expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy(); - }); - -
- * - * @element INPUT - * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, - * then special attribute "disabled" will be set on the element - */ - - -/** - * @ngdoc directive - * @name ngChecked - * @restrict A - * @priority 100 - * - * @description - * The HTML specification does not require browsers to preserve the values of boolean attributes - * such as checked. (Their presence means true and their absence means false.) - * If we put an Angular interpolation expression into such an attribute then the - * binding information would be lost when the browser removes the attribute. - * The `ngChecked` directive solves this problem for the `checked` attribute. - * This complementary directive is not removed by the browser and so provides - * a permanent reliable place to store the binding information. - * @example - - - Check me to check both:
- -
- - it('should check both checkBoxes', function() { - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); - element(by.model('master')).click(); - expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); - }); - -
- * - * @element INPUT - * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, - * then special attribute "checked" will be set on the element - */ - - -/** - * @ngdoc directive - * @name ngReadonly - * @restrict A - * @priority 100 - * - * @description - * The HTML specification does not require browsers to preserve the values of boolean attributes - * such as readonly. (Their presence means true and their absence means false.) - * If we put an Angular interpolation expression into such an attribute then the - * binding information would be lost when the browser removes the attribute. - * The `ngReadonly` directive solves this problem for the `readonly` attribute. - * This complementary directive is not removed by the browser and so provides - * a permanent reliable place to store the binding information. - * @example - - - Check me to make text readonly:
- -
- - it('should toggle readonly attr', function() { - expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy(); - element(by.model('checked')).click(); - expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy(); - }); - -
- * - * @element INPUT - * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, - * then special attribute "readonly" will be set on the element - */ - - -/** - * @ngdoc directive - * @name ngSelected - * @restrict A - * @priority 100 - * - * @description - * The HTML specification does not require browsers to preserve the values of boolean attributes - * such as selected. (Their presence means true and their absence means false.) - * If we put an Angular interpolation expression into such an attribute then the - * binding information would be lost when the browser removes the attribute. - * The `ngSelected` directive solves this problem for the `selected` attribute. - * This complementary directive is not removed by the browser and so provides - * a permanent reliable place to store the binding information. - * - * @example - - - Check me to select:
- -
- - it('should select Greetings!', function() { - expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy(); - element(by.model('selected')).click(); - expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy(); - }); - -
- * - * @element OPTION - * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, - * then special attribute "selected" will be set on the element - */ - -/** - * @ngdoc directive - * @name ngOpen - * @restrict A - * @priority 100 - * - * @description - * The HTML specification does not require browsers to preserve the values of boolean attributes - * such as open. (Their presence means true and their absence means false.) - * If we put an Angular interpolation expression into such an attribute then the - * binding information would be lost when the browser removes the attribute. - * The `ngOpen` directive solves this problem for the `open` attribute. - * This complementary directive is not removed by the browser and so provides - * a permanent reliable place to store the binding information. - * @example - - - Check me check multiple:
-
- Show/Hide me -
-
- - it('should toggle open', function() { - expect(element(by.id('details')).getAttribute('open')).toBeFalsy(); - element(by.model('open')).click(); - expect(element(by.id('details')).getAttribute('open')).toBeTruthy(); - }); - -
- * - * @element DETAILS - * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, - * then special attribute "open" will be set on the element - */ - -var ngAttributeAliasDirectives = {}; - - -// boolean attrs are evaluated -forEach(BOOLEAN_ATTR, function(propName, attrName) { - // binding to multiple is not supported - if (propName == "multiple") return; - - var normalized = directiveNormalize('ng-' + attrName); - ngAttributeAliasDirectives[normalized] = function() { - return { - priority: 100, - link: function(scope, element, attr) { - scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { - attr.$set(attrName, !!value); - }); - } - }; - }; -}); - - -// ng-src, ng-srcset, ng-href are interpolated -forEach(['src', 'srcset', 'href'], function(attrName) { - var normalized = directiveNormalize('ng-' + attrName); - ngAttributeAliasDirectives[normalized] = function() { - return { - priority: 99, // it needs to run after the attributes are interpolated - link: function(scope, element, attr) { - var propName = attrName, - name = attrName; - - if (attrName === 'href' && - toString.call(element.prop('href')) === '[object SVGAnimatedString]') { - name = 'xlinkHref'; - attr.$attr[name] = 'xlink:href'; - propName = null; - } - - attr.$observe(normalized, function(value) { - if (!value) { - if (attrName === 'href') { - attr.$set(name, null); - } - return; - } - - attr.$set(name, value); - - // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist - // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need - // to set the property as well to achieve the desired effect. - // we use attr[attrName] value since $set can sanitize the url. - if (msie && propName) element.prop(propName, attr[name]); - }); - } - }; - }; -}); - -/* global -nullFormCtrl */ -var nullFormCtrl = { - $addControl: noop, - $removeControl: noop, - $setValidity: noop, - $setDirty: noop, - $setPristine: noop -}; - -/** - * @ngdoc type - * @name form.FormController - * - * @property {boolean} $pristine True if user has not interacted with the form yet. - * @property {boolean} $dirty True if user has already interacted with the form. - * @property {boolean} $valid True if all of the containing forms and controls are valid. - * @property {boolean} $invalid True if at least one containing control or form is invalid. - * - * @property {Object} $error Is an object hash, containing references to all invalid controls or - * forms, where: - * - * - keys are validation tokens (error names), - * - values are arrays of controls or forms that are invalid for given error name. - * - * - * Built-in validation tokens: - * - * - `email` - * - `max` - * - `maxlength` - * - `min` - * - `minlength` - * - `number` - * - `pattern` - * - `required` - * - `url` - * - * @description - * `FormController` keeps track of all its controls and nested forms as well as the state of them, - * such as being valid/invalid or dirty/pristine. - * - * Each {@link ng.directive:form form} directive creates an instance - * of `FormController`. - * - */ -//asks for $scope to fool the BC controller module -FormController.$inject = ['$element', '$attrs', '$scope', '$animate']; -function FormController(element, attrs, $scope, $animate) { - var form = this, - parentForm = element.parent().controller('form') || nullFormCtrl, - invalidCount = 0, // used to easily determine if we are valid - errors = form.$error = {}, - controls = []; - - // init state - form.$name = attrs.name || attrs.ngForm; - form.$dirty = false; - form.$pristine = true; - form.$valid = true; - form.$invalid = false; - - parentForm.$addControl(form); - - // Setup initial state of the control - element.addClass(PRISTINE_CLASS); - toggleValidCss(true); - - // convenience method for easy toggling of classes - function toggleValidCss(isValid, validationErrorKey) { - validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; - $animate.setClass(element, - (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey, - (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey); - } - - /** - * @ngdoc method - * @name form.FormController#$addControl - * - * @description - * Register a control with the form. - * - * Input elements using ngModelController do this automatically when they are linked. - */ - form.$addControl = function(control) { - // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored - // and not added to the scope. Now we throw an error. - assertNotHasOwnProperty(control.$name, 'input'); - controls.push(control); - - if (control.$name) { - form[control.$name] = control; - } - }; - - /** - * @ngdoc method - * @name form.FormController#$removeControl - * - * @description - * Deregister a control from the form. - * - * Input elements using ngModelController do this automatically when they are destroyed. - */ - form.$removeControl = function(control) { - if (control.$name && form[control.$name] === control) { - delete form[control.$name]; - } - forEach(errors, function(queue, validationToken) { - form.$setValidity(validationToken, true, control); - }); - - arrayRemove(controls, control); - }; - - /** - * @ngdoc method - * @name form.FormController#$setValidity - * - * @description - * Sets the validity of a form control. - * - * This method will also propagate to parent forms. - */ - form.$setValidity = function(validationToken, isValid, control) { - var queue = errors[validationToken]; - - if (isValid) { - if (queue) { - arrayRemove(queue, control); - if (!queue.length) { - invalidCount--; - if (!invalidCount) { - toggleValidCss(isValid); - form.$valid = true; - form.$invalid = false; - } - errors[validationToken] = false; - toggleValidCss(true, validationToken); - parentForm.$setValidity(validationToken, true, form); - } - } - - } else { - if (!invalidCount) { - toggleValidCss(isValid); - } - if (queue) { - if (includes(queue, control)) return; - } else { - errors[validationToken] = queue = []; - invalidCount++; - toggleValidCss(false, validationToken); - parentForm.$setValidity(validationToken, false, form); - } - queue.push(control); - - form.$valid = false; - form.$invalid = true; - } - }; - - /** - * @ngdoc method - * @name form.FormController#$setDirty - * - * @description - * Sets the form to a dirty state. - * - * This method can be called to add the 'ng-dirty' class and set the form to a dirty - * state (ng-dirty class). This method will also propagate to parent forms. - */ - form.$setDirty = function() { - $animate.removeClass(element, PRISTINE_CLASS); - $animate.addClass(element, DIRTY_CLASS); - form.$dirty = true; - form.$pristine = false; - parentForm.$setDirty(); - }; - - /** - * @ngdoc method - * @name form.FormController#$setPristine - * - * @description - * Sets the form to its pristine state. - * - * This method can be called to remove the 'ng-dirty' class and set the form to its pristine - * state (ng-pristine class). This method will also propagate to all the controls contained - * in this form. - * - * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after - * saving or resetting it. - */ - form.$setPristine = function () { - $animate.removeClass(element, DIRTY_CLASS); - $animate.addClass(element, PRISTINE_CLASS); - form.$dirty = false; - form.$pristine = true; - forEach(controls, function(control) { - control.$setPristine(); - }); - }; -} - - -/** - * @ngdoc directive - * @name ngForm - * @restrict EAC - * - * @description - * Nestable alias of {@link ng.directive:form `form`} directive. HTML - * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a - * sub-group of controls needs to be determined. - * - * Note: the purpose of `ngForm` is to group controls, - * but not to be a replacement for the `
` tag with all of its capabilities - * (e.g. posting to the server, ...). - * - * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into - * related scope, under this name. - * - */ - - /** - * @ngdoc directive - * @name form - * @restrict E - * - * @description - * Directive that instantiates - * {@link form.FormController FormController}. - * - * If the `name` attribute is specified, the form controller is published onto the current scope under - * this name. - * - * # Alias: {@link ng.directive:ngForm `ngForm`} - * - * In Angular forms can be nested. This means that the outer form is valid when all of the child - * forms are valid as well. However, browsers do not allow nesting of `` elements, so - * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to - * `` but can be nested. This allows you to have nested forms, which is very useful when - * using Angular validation directives in forms that are dynamically generated using the - * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name` - * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an - * `ngForm` directive and nest these in an outer `form` element. - * - * - * # CSS classes - * - `ng-valid` is set if the form is valid. - * - `ng-invalid` is set if the form is invalid. - * - `ng-pristine` is set if the form is pristine. - * - `ng-dirty` is set if the form is dirty. - * - * Keep in mind that ngAnimate can detect each of these classes when added and removed. - * - * - * # Submitting a form and preventing the default action - * - * Since the role of forms in client-side Angular applications is different than in classical - * roundtrip apps, it is desirable for the browser not to translate the form submission into a full - * page reload that sends the data to the server. Instead some javascript logic should be triggered - * to handle the form submission in an application-specific way. - * - * For this reason, Angular prevents the default action (form submission to the server) unless the - * `` element has an `action` attribute specified. - * - * You can use one of the following two ways to specify what javascript method should be called when - * a form is submitted: - * - * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element - * - {@link ng.directive:ngClick ngClick} directive on the first - * button or input field of type submit (input[type=submit]) - * - * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit} - * or {@link ng.directive:ngClick ngClick} directives. - * This is because of the following form submission rules in the HTML specification: - * - * - If a form has only one input field then hitting enter in this field triggers form submit - * (`ngSubmit`) - * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter - * doesn't trigger submit - * - if a form has one or more input fields and one or more buttons or input[type=submit] then - * hitting enter in any of the input fields will trigger the click handler on the *first* button or - * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) - * - * - * ## Animation Hooks - * - * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. - * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any - * other validations that are performed within the form. Animations in ngForm are similar to how - * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well - * as JS animations. - * - * The following example shows a simple way to utilize CSS transitions to style a form element - * that has been rendered as invalid after it has been validated: - * - *
- * //be sure to include ngAnimate as a module to hook into more
- * //advanced animations
- * .my-form {
- *   transition:0.5s linear all;
- *   background: white;
- * }
- * .my-form.ng-invalid {
- *   background: red;
- *   color:white;
- * }
- * 
- * - * @example - - - - - - userType: - Required!
- userType = {{userType}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
- -
- - it('should initialize to model', function() { - var userType = element(by.binding('userType')); - var valid = element(by.binding('myForm.input.$valid')); - - expect(userType.getText()).toContain('guest'); - expect(valid.getText()).toContain('true'); - }); - - it('should be invalid if empty', function() { - var userType = element(by.binding('userType')); - var valid = element(by.binding('myForm.input.$valid')); - var userInput = element(by.model('userType')); - - userInput.clear(); - userInput.sendKeys(''); - - expect(userType.getText()).toEqual('userType ='); - expect(valid.getText()).toContain('false'); - }); - -
- * - * @param {string=} name Name of the form. If specified, the form controller will be published into - * related scope, under this name. - */ -var formDirectiveFactory = function(isNgForm) { - return ['$timeout', function($timeout) { - var formDirective = { - name: 'form', - restrict: isNgForm ? 'EAC' : 'E', - controller: FormController, - compile: function() { - return { - pre: function(scope, formElement, attr, controller) { - if (!attr.action) { - // we can't use jq events because if a form is destroyed during submission the default - // action is not prevented. see #1238 - // - // IE 9 is not affected because it doesn't fire a submit event and try to do a full - // page reload if the form was destroyed by submission of the form via a click handler - // on a button in the form. Looks like an IE9 specific bug. - var preventDefaultListener = function(event) { - event.preventDefault - ? event.preventDefault() - : event.returnValue = false; // IE - }; - - addEventListenerFn(formElement[0], 'submit', preventDefaultListener); - - // unregister the preventDefault listener so that we don't not leak memory but in a - // way that will achieve the prevention of the default action. - formElement.on('$destroy', function() { - $timeout(function() { - removeEventListenerFn(formElement[0], 'submit', preventDefaultListener); - }, 0, false); - }); - } - - var parentFormCtrl = formElement.parent().controller('form'), - alias = attr.name || attr.ngForm; - - if (alias) { - setter(scope, alias, controller, alias); - } - if (parentFormCtrl) { - formElement.on('$destroy', function() { - parentFormCtrl.$removeControl(controller); - if (alias) { - setter(scope, alias, undefined, alias); - } - extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards - }); - } - } - }; - } - }; - - return formDirective; - }]; -}; - -var formDirective = formDirectiveFactory(); -var ngFormDirective = formDirectiveFactory(true); - -/* global VALID_CLASS: true, - INVALID_CLASS: true, - PRISTINE_CLASS: true, - DIRTY_CLASS: true -*/ - -var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; -var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i; -var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; - -var inputType = { - - /** - * @ngdoc input - * @name input[text] - * - * @description - * Standard HTML text input with angular data binding, inherited by most of the `input` elements. - * - * *NOTE* Not every feature offered is available for all input types. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} required Adds `required` validation error key if the value is not entered. - * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to - * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of - * `required` when you want to data-bind to the `required` attribute. - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. - * This parameter is ignored for input[type=password] controls, which will never trim the - * input. - * - * @example - - - -
- Single word: - - Required! - - Single word only! - - text = {{text}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
-
-
- - var text = element(by.binding('text')); - var valid = element(by.binding('myForm.input.$valid')); - var input = element(by.model('text')); - - it('should initialize to model', function() { - expect(text.getText()).toContain('guest'); - expect(valid.getText()).toContain('true'); - }); - - it('should be invalid if empty', function() { - input.clear(); - input.sendKeys(''); - - expect(text.getText()).toEqual('text ='); - expect(valid.getText()).toContain('false'); - }); - - it('should be invalid if multi word', function() { - input.clear(); - input.sendKeys('hello world'); - - expect(valid.getText()).toContain('false'); - }); - -
- */ - 'text': textInputType, - - - /** - * @ngdoc input - * @name input[number] - * - * @description - * Text input with number validation and transformation. Sets the `number` validation - * error if not a valid number. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. - * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. - * @param {string=} required Sets `required` validation error key if the value is not entered. - * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to - * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of - * `required` when you want to data-bind to the `required` attribute. - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * - * @example - - - -
- Number: - - Required! - - Not valid number! - value = {{value}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
-
-
- - var value = element(by.binding('value')); - var valid = element(by.binding('myForm.input.$valid')); - var input = element(by.model('value')); - - it('should initialize to model', function() { - expect(value.getText()).toContain('12'); - expect(valid.getText()).toContain('true'); - }); - - it('should be invalid if empty', function() { - input.clear(); - input.sendKeys(''); - expect(value.getText()).toEqual('value ='); - expect(valid.getText()).toContain('false'); - }); - - it('should be invalid if over max', function() { - input.clear(); - input.sendKeys('123'); - expect(value.getText()).toEqual('value ='); - expect(valid.getText()).toContain('false'); - }); - -
- */ - 'number': numberInputType, - - - /** - * @ngdoc input - * @name input[url] - * - * @description - * Text input with URL validation. Sets the `url` validation error key if the content is not a - * valid URL. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} required Sets `required` validation error key if the value is not entered. - * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to - * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of - * `required` when you want to data-bind to the `required` attribute. - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * - * @example - - - -
- URL: - - Required! - - Not valid url! - text = {{text}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
- myForm.$error.url = {{!!myForm.$error.url}}
-
-
- - var text = element(by.binding('text')); - var valid = element(by.binding('myForm.input.$valid')); - var input = element(by.model('text')); - - it('should initialize to model', function() { - expect(text.getText()).toContain('http://google.com'); - expect(valid.getText()).toContain('true'); - }); - - it('should be invalid if empty', function() { - input.clear(); - input.sendKeys(''); - - expect(text.getText()).toEqual('text ='); - expect(valid.getText()).toContain('false'); - }); - - it('should be invalid if not url', function() { - input.clear(); - input.sendKeys('box'); - - expect(valid.getText()).toContain('false'); - }); - -
- */ - 'url': urlInputType, - - - /** - * @ngdoc input - * @name input[email] - * - * @description - * Text input with email validation. Sets the `email` validation error key if not a valid email - * address. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} required Sets `required` validation error key if the value is not entered. - * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to - * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of - * `required` when you want to data-bind to the `required` attribute. - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * - * @example - - - -
- Email: - - Required! - - Not valid email! - text = {{text}}
- myForm.input.$valid = {{myForm.input.$valid}}
- myForm.input.$error = {{myForm.input.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
- myForm.$error.email = {{!!myForm.$error.email}}
-
-
- - var text = element(by.binding('text')); - var valid = element(by.binding('myForm.input.$valid')); - var input = element(by.model('text')); - - it('should initialize to model', function() { - expect(text.getText()).toContain('me@example.com'); - expect(valid.getText()).toContain('true'); - }); - - it('should be invalid if empty', function() { - input.clear(); - input.sendKeys(''); - expect(text.getText()).toEqual('text ='); - expect(valid.getText()).toContain('false'); - }); - - it('should be invalid if not email', function() { - input.clear(); - input.sendKeys('xxx'); - - expect(valid.getText()).toContain('false'); - }); - -
- */ - 'email': emailInputType, - - - /** - * @ngdoc input - * @name input[radio] - * - * @description - * HTML radio button. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string} value The value to which the expression should be set when selected. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * @param {string} ngValue Angular expression which sets the value to which the expression should - * be set when selected. - * - * @example - - - -
- Red
- Green
- Blue
- color = {{color | json}}
-
- Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`. -
- - it('should change state', function() { - var color = element(by.binding('color')); - - expect(color.getText()).toContain('blue'); - - element.all(by.model('color')).get(0).click(); - - expect(color.getText()).toContain('red'); - }); - -
- */ - 'radio': radioInputType, - - - /** - * @ngdoc input - * @name input[checkbox] - * - * @description - * HTML checkbox. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} ngTrueValue The value to which the expression should be set when selected. - * @param {string=} ngFalseValue The value to which the expression should be set when not selected. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * - * @example - - - -
- Value1:
- Value2:
- value1 = {{value1}}
- value2 = {{value2}}
-
-
- - it('should change state', function() { - var value1 = element(by.binding('value1')); - var value2 = element(by.binding('value2')); - - expect(value1.getText()).toContain('true'); - expect(value2.getText()).toContain('YES'); - - element(by.model('value1')).click(); - element(by.model('value2')).click(); - - expect(value1.getText()).toContain('false'); - expect(value2.getText()).toContain('NO'); - }); - -
- */ - 'checkbox': checkboxInputType, - - 'hidden': noop, - 'button': noop, - 'submit': noop, - 'reset': noop, - 'file': noop -}; - -// A helper function to call $setValidity and return the value / undefined, -// a pattern that is repeated a lot in the input validation logic. -function validate(ctrl, validatorName, validity, value){ - ctrl.$setValidity(validatorName, validity); - return validity ? value : undefined; -} - -function testFlags(validity, flags) { - var i, flag; - if (flags) { - for (i=0; i= minlength, value); - }; - - ctrl.$parsers.push(minLengthValidator); - ctrl.$formatters.push(minLengthValidator); - } - - // max length validator - if (attr.ngMaxlength) { - var maxlength = int(attr.ngMaxlength); - var maxLengthValidator = function(value) { - return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value); - }; - - ctrl.$parsers.push(maxLengthValidator); - ctrl.$formatters.push(maxLengthValidator); - } -} - -var numberBadFlags = ['badInput']; - -function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { - textInputType(scope, element, attr, ctrl, $sniffer, $browser); - - ctrl.$parsers.push(function(value) { - var empty = ctrl.$isEmpty(value); - if (empty || NUMBER_REGEXP.test(value)) { - ctrl.$setValidity('number', true); - return value === '' ? null : (empty ? value : parseFloat(value)); - } else { - ctrl.$setValidity('number', false); - return undefined; - } - }); - - addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState); - - ctrl.$formatters.push(function(value) { - return ctrl.$isEmpty(value) ? '' : '' + value; - }); - - if (attr.min) { - var minValidator = function(value) { - var min = parseFloat(attr.min); - return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value); - }; - - ctrl.$parsers.push(minValidator); - ctrl.$formatters.push(minValidator); - } - - if (attr.max) { - var maxValidator = function(value) { - var max = parseFloat(attr.max); - return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value); - }; - - ctrl.$parsers.push(maxValidator); - ctrl.$formatters.push(maxValidator); - } - - ctrl.$formatters.push(function(value) { - return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value); - }); -} - -function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { - textInputType(scope, element, attr, ctrl, $sniffer, $browser); - - var urlValidator = function(value) { - return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value); - }; - - ctrl.$formatters.push(urlValidator); - ctrl.$parsers.push(urlValidator); -} - -function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { - textInputType(scope, element, attr, ctrl, $sniffer, $browser); - - var emailValidator = function(value) { - return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value); - }; - - ctrl.$formatters.push(emailValidator); - ctrl.$parsers.push(emailValidator); -} - -function radioInputType(scope, element, attr, ctrl) { - // make the name unique, if not defined - if (isUndefined(attr.name)) { - element.attr('name', nextUid()); - } - - element.on('click', function() { - if (element[0].checked) { - scope.$apply(function() { - ctrl.$setViewValue(attr.value); - }); - } - }); - - ctrl.$render = function() { - var value = attr.value; - element[0].checked = (value == ctrl.$viewValue); - }; - - attr.$observe('value', ctrl.$render); -} - -function checkboxInputType(scope, element, attr, ctrl) { - var trueValue = attr.ngTrueValue, - falseValue = attr.ngFalseValue; - - if (!isString(trueValue)) trueValue = true; - if (!isString(falseValue)) falseValue = false; - - element.on('click', function() { - scope.$apply(function() { - ctrl.$setViewValue(element[0].checked); - }); - }); - - ctrl.$render = function() { - element[0].checked = ctrl.$viewValue; - }; - - // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox. - ctrl.$isEmpty = function(value) { - return value !== trueValue; - }; - - ctrl.$formatters.push(function(value) { - return value === trueValue; - }); - - ctrl.$parsers.push(function(value) { - return value ? trueValue : falseValue; - }); -} - - -/** - * @ngdoc directive - * @name textarea - * @restrict E - * - * @description - * HTML textarea element control with angular data-binding. The data-binding and validation - * properties of this element are exactly the same as those of the - * {@link ng.directive:input input element}. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} required Sets `required` validation error key if the value is not entered. - * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to - * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of - * `required` when you want to data-bind to the `required` attribute. - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. - */ - - -/** - * @ngdoc directive - * @name input - * @restrict E - * - * @description - * HTML input element control with angular data-binding. Input control follows HTML5 input types - * and polyfills the HTML5 validation behavior for older browsers. - * - * *NOTE* Not every feature offered is available for all input types. - * - * @param {string} ngModel Assignable angular expression to data-bind to. - * @param {string=} name Property name of the form under which the control is published. - * @param {string=} required Sets `required` validation error key if the value is not entered. - * @param {boolean=} ngRequired Sets `required` attribute if set to true - * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than - * minlength. - * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than - * maxlength. - * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the - * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for - * patterns defined as scope expressions. - * @param {string=} ngChange Angular expression to be executed when input changes due to user - * interaction with the input element. - * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. - * This parameter is ignored for input[type=password] controls, which will never trim the - * input. - * - * @example - - - -
-
- User name: - - Required!
- Last name: - - Too short! - - Too long!
-
-
- user = {{user}}
- myForm.userName.$valid = {{myForm.userName.$valid}}
- myForm.userName.$error = {{myForm.userName.$error}}
- myForm.lastName.$valid = {{myForm.lastName.$valid}}
- myForm.lastName.$error = {{myForm.lastName.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
- myForm.$error.minlength = {{!!myForm.$error.minlength}}
- myForm.$error.maxlength = {{!!myForm.$error.maxlength}}
-
-
- - var user = element(by.binding('{{user}}')); - var userNameValid = element(by.binding('myForm.userName.$valid')); - var lastNameValid = element(by.binding('myForm.lastName.$valid')); - var lastNameError = element(by.binding('myForm.lastName.$error')); - var formValid = element(by.binding('myForm.$valid')); - var userNameInput = element(by.model('user.name')); - var userLastInput = element(by.model('user.last')); - - it('should initialize to model', function() { - expect(user.getText()).toContain('{"name":"guest","last":"visitor"}'); - expect(userNameValid.getText()).toContain('true'); - expect(formValid.getText()).toContain('true'); - }); - - it('should be invalid if empty when required', function() { - userNameInput.clear(); - userNameInput.sendKeys(''); - - expect(user.getText()).toContain('{"last":"visitor"}'); - expect(userNameValid.getText()).toContain('false'); - expect(formValid.getText()).toContain('false'); - }); - - it('should be valid if empty when min length is set', function() { - userLastInput.clear(); - userLastInput.sendKeys(''); - - expect(user.getText()).toContain('{"name":"guest","last":""}'); - expect(lastNameValid.getText()).toContain('true'); - expect(formValid.getText()).toContain('true'); - }); - - it('should be invalid if less than required min length', function() { - userLastInput.clear(); - userLastInput.sendKeys('xx'); - - expect(user.getText()).toContain('{"name":"guest"}'); - expect(lastNameValid.getText()).toContain('false'); - expect(lastNameError.getText()).toContain('minlength'); - expect(formValid.getText()).toContain('false'); - }); - - it('should be invalid if longer than max length', function() { - userLastInput.clear(); - userLastInput.sendKeys('some ridiculously long name'); - - expect(user.getText()).toContain('{"name":"guest"}'); - expect(lastNameValid.getText()).toContain('false'); - expect(lastNameError.getText()).toContain('maxlength'); - expect(formValid.getText()).toContain('false'); - }); - -
- */ -var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) { - return { - restrict: 'E', - require: '?ngModel', - link: function(scope, element, attr, ctrl) { - if (ctrl) { - (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer, - $browser); - } - } - }; -}]; - -var VALID_CLASS = 'ng-valid', - INVALID_CLASS = 'ng-invalid', - PRISTINE_CLASS = 'ng-pristine', - DIRTY_CLASS = 'ng-dirty'; - -/** - * @ngdoc type - * @name ngModel.NgModelController - * - * @property {string} $viewValue Actual string value in the view. - * @property {*} $modelValue The value in the model, that the control is bound to. - * @property {Array.} $parsers Array of functions to execute, as a pipeline, whenever - the control reads value from the DOM. Each function is called, in turn, passing the value - through to the next. The last return value is used to populate the model. - Used to sanitize / convert the value as well as validation. For validation, - the parsers should update the validity state using - {@link ngModel.NgModelController#$setValidity $setValidity()}, - and return `undefined` for invalid values. - - * - * @property {Array.} $formatters Array of functions to execute, as a pipeline, whenever - the model value changes. Each function is called, in turn, passing the value through to the - next. Used to format / convert values for display in the control and validation. - * ```js - * function formatter(value) { - * if (value) { - * return value.toUpperCase(); - * } - * } - * ngModel.$formatters.push(formatter); - * ``` - * - * @property {Array.} $viewChangeListeners Array of functions to execute whenever the - * view value has changed. It is called with no arguments, and its return value is ignored. - * This can be used in place of additional $watches against the model value. - * - * @property {Object} $error An object hash with all errors as keys. - * - * @property {boolean} $pristine True if user has not interacted with the control yet. - * @property {boolean} $dirty True if user has already interacted with the control. - * @property {boolean} $valid True if there is no error. - * @property {boolean} $invalid True if at least one error on the control. - * - * @description - * - * `NgModelController` provides API for the `ng-model` directive. The controller contains - * services for data-binding, validation, CSS updates, and value formatting and parsing. It - * purposefully does not contain any logic which deals with DOM rendering or listening to - * DOM events. Such DOM related logic should be provided by other directives which make use of - * `NgModelController` for data-binding. - * - * ## Custom Control Example - * This example shows how to use `NgModelController` with a custom control to achieve - * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`) - * collaborate together to achieve the desired result. - * - * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element - * contents be edited in place by the user. This will not work on older browsers. - * - * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize} - * module to automatically remove "bad" content like inline event listener (e.g. ``). - * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks - * that content using the `$sce` service. - * - * - - [contenteditable] { - border: 1px solid black; - background-color: white; - min-height: 20px; - } - - .ng-invalid { - border: 1px solid red; - } - - - - angular.module('customControl', ['ngSanitize']). - directive('contenteditable', ['$sce', function($sce) { - return { - restrict: 'A', // only activate on element attribute - require: '?ngModel', // get a hold of NgModelController - link: function(scope, element, attrs, ngModel) { - if(!ngModel) return; // do nothing if no ng-model - - // Specify how UI should be updated - ngModel.$render = function() { - element.html($sce.getTrustedHtml(ngModel.$viewValue || '')); - }; - - // Listen for change events to enable binding - element.on('blur keyup change', function() { - scope.$evalAsync(read); - }); - read(); // initialize - - // Write data to the model - function read() { - var html = element.html(); - // When we clear the content editable the browser leaves a
behind - // If strip-br attribute is provided then we strip this out - if( attrs.stripBr && html == '
' ) { - html = ''; - } - ngModel.$setViewValue(html); - } - } - }; - }]); -
- -
-
Change me!
- Required! -
- -
-
- - it('should data-bind and become invalid', function() { - if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') { - // SafariDriver can't handle contenteditable - // and Firefox driver can't clear contenteditables very well - return; - } - var contentEditable = element(by.css('[contenteditable]')); - var content = 'Change me!'; - - expect(contentEditable.getText()).toEqual(content); - - contentEditable.clear(); - contentEditable.sendKeys(protractor.Key.BACK_SPACE); - expect(contentEditable.getText()).toEqual(''); - expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/); - }); - - *
- * - * - */ -var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', - function($scope, $exceptionHandler, $attr, $element, $parse, $animate) { - this.$viewValue = Number.NaN; - this.$modelValue = Number.NaN; - this.$parsers = []; - this.$formatters = []; - this.$viewChangeListeners = []; - this.$pristine = true; - this.$dirty = false; - this.$valid = true; - this.$invalid = false; - this.$name = $attr.name; - - var ngModelGet = $parse($attr.ngModel), - ngModelSet = ngModelGet.assign; - - if (!ngModelSet) { - throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}", - $attr.ngModel, startingTag($element)); - } - - /** - * @ngdoc method - * @name ngModel.NgModelController#$render - * - * @description - * Called when the view needs to be updated. It is expected that the user of the ng-model - * directive will implement this method. - */ - this.$render = noop; - - /** - * @ngdoc method - * @name ngModel.NgModelController#$isEmpty - * - * @description - * This is called when we need to determine if the value of the input is empty. - * - * For instance, the required directive does this to work out if the input has data or not. - * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`. - * - * You can override this for input directives whose concept of being empty is different to the - * default. The `checkboxInputType` directive does this because in its case a value of `false` - * implies empty. - * - * @param {*} value Reference to check. - * @returns {boolean} True if `value` is empty. - */ - this.$isEmpty = function(value) { - return isUndefined(value) || value === '' || value === null || value !== value; - }; - - var parentForm = $element.inheritedData('$formController') || nullFormCtrl, - invalidCount = 0, // used to easily determine if we are valid - $error = this.$error = {}; // keep invalid keys here - - - // Setup initial state of the control - $element.addClass(PRISTINE_CLASS); - toggleValidCss(true); - - // convenience method for easy toggling of classes - function toggleValidCss(isValid, validationErrorKey) { - validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : ''; - $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey); - $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey); - } - - /** - * @ngdoc method - * @name ngModel.NgModelController#$setValidity - * - * @description - * Change the validity state, and notifies the form when the control changes validity. (i.e. it - * does not notify form if given validator is already marked as invalid). - * - * This method should be called by validators - i.e. the parser or formatter functions. - * - * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign - * to `$error[validationErrorKey]=!isValid` so that it is available for data-binding. - * The `validationErrorKey` should be in camelCase and will get converted into dash-case - * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error` - * class and can be bound to as `{{someForm.someControl.$error.myError}}` . - * @param {boolean} isValid Whether the current state is valid (true) or invalid (false). - */ - this.$setValidity = function(validationErrorKey, isValid) { - // Purposeful use of ! here to cast isValid to boolean in case it is undefined - // jshint -W018 - if ($error[validationErrorKey] === !isValid) return; - // jshint +W018 - - if (isValid) { - if ($error[validationErrorKey]) invalidCount--; - if (!invalidCount) { - toggleValidCss(true); - this.$valid = true; - this.$invalid = false; - } - } else { - toggleValidCss(false); - this.$invalid = true; - this.$valid = false; - invalidCount++; - } - - $error[validationErrorKey] = !isValid; - toggleValidCss(isValid, validationErrorKey); - - parentForm.$setValidity(validationErrorKey, isValid, this); - }; - - /** - * @ngdoc method - * @name ngModel.NgModelController#$setPristine - * - * @description - * Sets the control to its pristine state. - * - * This method can be called to remove the 'ng-dirty' class and set the control to its pristine - * state (ng-pristine class). - */ - this.$setPristine = function () { - this.$dirty = false; - this.$pristine = true; - $animate.removeClass($element, DIRTY_CLASS); - $animate.addClass($element, PRISTINE_CLASS); - }; - - /** - * @ngdoc method - * @name ngModel.NgModelController#$setViewValue - * - * @description - * Update the view value. - * - * This method should be called when the view value changes, typically from within a DOM event handler. - * For example {@link ng.directive:input input} and - * {@link ng.directive:select select} directives call it. - * - * It will update the $viewValue, then pass this value through each of the functions in `$parsers`, - * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to - * `$modelValue` and the **expression** specified in the `ng-model` attribute. - * - * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called. - * - * Note that calling this function does not trigger a `$digest`. - * - * @param {string} value Value from the view. - */ - this.$setViewValue = function(value) { - this.$viewValue = value; - - // change to dirty - if (this.$pristine) { - this.$dirty = true; - this.$pristine = false; - $animate.removeClass($element, PRISTINE_CLASS); - $animate.addClass($element, DIRTY_CLASS); - parentForm.$setDirty(); - } - - forEach(this.$parsers, function(fn) { - value = fn(value); - }); - - if (this.$modelValue !== value) { - this.$modelValue = value; - ngModelSet($scope, value); - forEach(this.$viewChangeListeners, function(listener) { - try { - listener(); - } catch(e) { - $exceptionHandler(e); - } - }); - } - }; - - // model -> value - var ctrl = this; - - $scope.$watch(function ngModelWatch() { - var value = ngModelGet($scope); - - // if scope model value and ngModel value are out of sync - if (ctrl.$modelValue !== value) { - - var formatters = ctrl.$formatters, - idx = formatters.length; - - ctrl.$modelValue = value; - while(idx--) { - value = formatters[idx](value); - } - - if (ctrl.$viewValue !== value) { - ctrl.$viewValue = value; - ctrl.$render(); - } - } - - return value; - }); -}]; - - -/** - * @ngdoc directive - * @name ngModel - * - * @element input - * - * @description - * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a - * property on the scope using {@link ngModel.NgModelController NgModelController}, - * which is created and exposed by this directive. - * - * `ngModel` is responsible for: - * - * - Binding the view into the model, which other directives such as `input`, `textarea` or `select` - * require. - * - Providing validation behavior (i.e. required, number, email, url). - * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors). - * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations. - * - Registering the control with its parent {@link ng.directive:form form}. - * - * Note: `ngModel` will try to bind to the property given by evaluating the expression on the - * current scope. If the property doesn't already exist on this scope, it will be created - * implicitly and added to the scope. - * - * For best practices on using `ngModel`, see: - * - * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes) - * - * For basic examples, how to use `ngModel`, see: - * - * - {@link ng.directive:input input} - * - {@link input[text] text} - * - {@link input[checkbox] checkbox} - * - {@link input[radio] radio} - * - {@link input[number] number} - * - {@link input[email] email} - * - {@link input[url] url} - * - {@link ng.directive:select select} - * - {@link ng.directive:textarea textarea} - * - * # CSS classes - * The following CSS classes are added and removed on the associated input/select/textarea element - * depending on the validity of the model. - * - * - `ng-valid` is set if the model is valid. - * - `ng-invalid` is set if the model is invalid. - * - `ng-pristine` is set if the model is pristine. - * - `ng-dirty` is set if the model is dirty. - * - * Keep in mind that ngAnimate can detect each of these classes when added and removed. - * - * ## Animation Hooks - * - * Animations within models are triggered when any of the associated CSS classes are added and removed - * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`, - * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself. - * The animations that are triggered within ngModel are similar to how they work in ngClass and - * animations can be hooked into using CSS transitions, keyframes as well as JS animations. - * - * The following example shows a simple way to utilize CSS transitions to style an input element - * that has been rendered as invalid after it has been validated: - * - *
- * //be sure to include ngAnimate as a module to hook into more
- * //advanced animations
- * .my-input {
- *   transition:0.5s linear all;
- *   background: white;
- * }
- * .my-input.ng-invalid {
- *   background: red;
- *   color:white;
- * }
- * 
- * - * @example - * - - - - Update input to see transitions when valid/invalid. - Integer is a valid value. -
- -
-
- *
- */ -var ngModelDirective = function() { - return { - require: ['ngModel', '^?form'], - controller: NgModelController, - link: function(scope, element, attr, ctrls) { - // notify others, especially parent forms - - var modelCtrl = ctrls[0], - formCtrl = ctrls[1] || nullFormCtrl; - - formCtrl.$addControl(modelCtrl); - - scope.$on('$destroy', function() { - formCtrl.$removeControl(modelCtrl); - }); - } - }; -}; - - -/** - * @ngdoc directive - * @name ngChange - * - * @description - * Evaluate the given expression when the user changes the input. - * The expression is evaluated immediately, unlike the JavaScript onchange event - * which only triggers at the end of a change (usually, when the user leaves the - * form element or presses the return key). - * The expression is not evaluated when the value change is coming from the model. - * - * Note, this directive requires `ngModel` to be present. - * - * @element input - * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change - * in input value. - * - * @example - * - * - * - *
- * - * - *
- * debug = {{confirmed}}
- * counter = {{counter}}
- *
- *
- * - * var counter = element(by.binding('counter')); - * var debug = element(by.binding('confirmed')); - * - * it('should evaluate the expression if changing from view', function() { - * expect(counter.getText()).toContain('0'); - * - * element(by.id('ng-change-example1')).click(); - * - * expect(counter.getText()).toContain('1'); - * expect(debug.getText()).toContain('true'); - * }); - * - * it('should not evaluate the expression if changing from model', function() { - * element(by.id('ng-change-example2')).click(); - - * expect(counter.getText()).toContain('0'); - * expect(debug.getText()).toContain('true'); - * }); - * - *
- */ -var ngChangeDirective = valueFn({ - require: 'ngModel', - link: function(scope, element, attr, ctrl) { - ctrl.$viewChangeListeners.push(function() { - scope.$eval(attr.ngChange); - }); - } -}); - - -var requiredDirective = function() { - return { - require: '?ngModel', - link: function(scope, elm, attr, ctrl) { - if (!ctrl) return; - attr.required = true; // force truthy in case we are on non input element - - var validator = function(value) { - if (attr.required && ctrl.$isEmpty(value)) { - ctrl.$setValidity('required', false); - return; - } else { - ctrl.$setValidity('required', true); - return value; - } - }; - - ctrl.$formatters.push(validator); - ctrl.$parsers.unshift(validator); - - attr.$observe('required', function() { - validator(ctrl.$viewValue); - }); - } - }; -}; - - -/** - * @ngdoc directive - * @name ngList - * - * @description - * Text input that converts between a delimited string and an array of strings. The delimiter - * can be a fixed string (by default a comma) or a regular expression. - * - * @element input - * @param {string=} ngList optional delimiter that should be used to split the value. If - * specified in form `/something/` then the value will be converted into a regular expression. - * - * @example - - - -
- List: - - Required! -
- names = {{names}}
- myForm.namesInput.$valid = {{myForm.namesInput.$valid}}
- myForm.namesInput.$error = {{myForm.namesInput.$error}}
- myForm.$valid = {{myForm.$valid}}
- myForm.$error.required = {{!!myForm.$error.required}}
-
-
- - var listInput = element(by.model('names')); - var names = element(by.binding('{{names}}')); - var valid = element(by.binding('myForm.namesInput.$valid')); - var error = element(by.css('span.error')); - - it('should initialize to model', function() { - expect(names.getText()).toContain('["igor","misko","vojta"]'); - expect(valid.getText()).toContain('true'); - expect(error.getCssValue('display')).toBe('none'); - }); - - it('should be invalid if empty', function() { - listInput.clear(); - listInput.sendKeys(''); - - expect(names.getText()).toContain(''); - expect(valid.getText()).toContain('false'); - expect(error.getCssValue('display')).not.toBe('none'); }); - -
- */ -var ngListDirective = function() { - return { - require: 'ngModel', - link: function(scope, element, attr, ctrl) { - var match = /\/(.*)\//.exec(attr.ngList), - separator = match && new RegExp(match[1]) || attr.ngList || ','; - - var parse = function(viewValue) { - // If the viewValue is invalid (say required but empty) it will be `undefined` - if (isUndefined(viewValue)) return; - - var list = []; - - if (viewValue) { - forEach(viewValue.split(separator), function(value) { - if (value) list.push(trim(value)); - }); - } - - return list; - }; - - ctrl.$parsers.push(parse); - ctrl.$formatters.push(function(value) { - if (isArray(value)) { - return value.join(', '); - } - - return undefined; - }); - - // Override the standard $isEmpty because an empty array means the input is empty. - ctrl.$isEmpty = function(value) { - return !value || !value.length; - }; - } - }; -}; - - -var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; -/** - * @ngdoc directive - * @name ngValue - * - * @description - * Binds the given expression to the value of `input[select]` or `input[radio]`, so - * that when the element is selected, the `ngModel` of that element is set to the - * bound value. - * - * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as - * shown below. - * - * @element input - * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute - * of the `input` element - * - * @example - - - -
-

Which is your favorite?

- -
You chose {{my.favorite}}
-
-
- - var favorite = element(by.binding('my.favorite')); - - it('should initialize to model', function() { - expect(favorite.getText()).toContain('unicorns'); - }); - it('should bind the values to the inputs', function() { - element.all(by.model('my.favorite')).get(0).click(); - expect(favorite.getText()).toContain('pizza'); - }); - -
- */ -var ngValueDirective = function() { - return { - priority: 100, - compile: function(tpl, tplAttr) { - if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) { - return function ngValueConstantLink(scope, elm, attr) { - attr.$set('value', scope.$eval(attr.ngValue)); - }; - } else { - return function ngValueLink(scope, elm, attr) { - scope.$watch(attr.ngValue, function valueWatchAction(value) { - attr.$set('value', value); - }); - }; - } - } - }; -}; - -/** - * @ngdoc directive - * @name ngBind - * @restrict AC - * - * @description - * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element - * with the value of a given expression, and to update the text content when the value of that - * expression changes. - * - * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like - * `{{ expression }}` which is similar but less verbose. - * - * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily - * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an - * element attribute, it makes the bindings invisible to the user while the page is loading. - * - * An alternative solution to this problem would be using the - * {@link ng.directive:ngCloak ngCloak} directive. - * - * - * @element ANY - * @param {expression} ngBind {@link guide/expression Expression} to evaluate. - * - * @example - * Enter a name in the Live Preview text box; the greeting below the text box changes instantly. - - - -
- Enter name:
- Hello ! -
-
- - it('should check ng-bind', function() { - var nameInput = element(by.model('name')); - - expect(element(by.binding('name')).getText()).toBe('Whirled'); - nameInput.clear(); - nameInput.sendKeys('world'); - expect(element(by.binding('name')).getText()).toBe('world'); - }); - -
- */ -var ngBindDirective = ngDirective({ - compile: function(templateElement) { - templateElement.addClass('ng-binding'); - return function (scope, element, attr) { - element.data('$binding', attr.ngBind); - scope.$watch(attr.ngBind, function ngBindWatchAction(value) { - // We are purposefully using == here rather than === because we want to - // catch when value is "null or undefined" - // jshint -W041 - element.text(value == undefined ? '' : value); - }); - }; - } -}); - - -/** - * @ngdoc directive - * @name ngBindTemplate - * - * @description - * The `ngBindTemplate` directive specifies that the element - * text content should be replaced with the interpolation of the template - * in the `ngBindTemplate` attribute. - * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}` - * expressions. This directive is needed since some HTML elements - * (such as TITLE and OPTION) cannot contain SPAN elements. - * - * @element ANY - * @param {string} ngBindTemplate template of form - * {{ expression }} to eval. - * - * @example - * Try it here: enter text in text box and watch the greeting change. - - - -
- Salutation:
- Name:
-

-       
-
- - it('should check ng-bind', function() { - var salutationElem = element(by.binding('salutation')); - var salutationInput = element(by.model('salutation')); - var nameInput = element(by.model('name')); - - expect(salutationElem.getText()).toBe('Hello World!'); - - salutationInput.clear(); - salutationInput.sendKeys('Greetings'); - nameInput.clear(); - nameInput.sendKeys('user'); - - expect(salutationElem.getText()).toBe('Greetings user!'); - }); - -
- */ -var ngBindTemplateDirective = ['$interpolate', function($interpolate) { - return function(scope, element, attr) { - // TODO: move this to scenario runner - var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate)); - element.addClass('ng-binding').data('$binding', interpolateFn); - attr.$observe('ngBindTemplate', function(value) { - element.text(value); - }); - }; -}]; - - -/** - * @ngdoc directive - * @name ngBindHtml - * - * @description - * Creates a binding that will innerHTML the result of evaluating the `expression` into the current - * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link - * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize` - * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in - * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to - * include "angular-sanitize.js" in your application. - * - * You may also bypass sanitization for values you know are safe. To do so, bind to - * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example - * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}. - * - * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you - * will have an exception (instead of an exploit.) - * - * @element ANY - * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate. - * - * @example - - - -
-

-
-
- - - angular.module('bindHtmlExample', ['ngSanitize']) - .controller('ExampleController', ['$scope', function($scope) { - $scope.myHTML = - 'I am an HTMLstring with ' + - 'links! and other stuff'; - }]); - - - - it('should check ng-bind-html', function() { - expect(element(by.binding('myHTML')).getText()).toBe( - 'I am an HTMLstring with links! and other stuff'); - }); - -
- */ -var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { - return { - compile: function (tElement) { - tElement.addClass('ng-binding'); - - return function (scope, element, attr) { - element.data('$binding', attr.ngBindHtml); - - var parsed = $parse(attr.ngBindHtml); - - function getStringValue() { - return (parsed(scope) || '').toString(); - } - - scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) { - element.html($sce.getTrustedHtml(parsed(scope)) || ''); - }); - }; - } - }; -}]; - -function classDirective(name, selector) { - name = 'ngClass' + name; - return ['$animate', function($animate) { - return { - restrict: 'AC', - link: function(scope, element, attr) { - var oldVal; - - scope.$watch(attr[name], ngClassWatchAction, true); - - attr.$observe('class', function(value) { - ngClassWatchAction(scope.$eval(attr[name])); - }); - - - if (name !== 'ngClass') { - scope.$watch('$index', function($index, old$index) { - // jshint bitwise: false - var mod = $index & 1; - if (mod !== (old$index & 1)) { - var classes = arrayClasses(scope.$eval(attr[name])); - mod === selector ? - addClasses(classes) : - removeClasses(classes); - } - }); - } - - function addClasses(classes) { - var newClasses = digestClassCounts(classes, 1); - attr.$addClass(newClasses); - } - - function removeClasses(classes) { - var newClasses = digestClassCounts(classes, -1); - attr.$removeClass(newClasses); - } - - function digestClassCounts (classes, count) { - var classCounts = element.data('$classCounts') || {}; - var classesToUpdate = []; - forEach(classes, function (className) { - if (count > 0 || classCounts[className]) { - classCounts[className] = (classCounts[className] || 0) + count; - if (classCounts[className] === +(count > 0)) { - classesToUpdate.push(className); - } - } - }); - element.data('$classCounts', classCounts); - return classesToUpdate.join(' '); - } - - function updateClasses (oldClasses, newClasses) { - var toAdd = arrayDifference(newClasses, oldClasses); - var toRemove = arrayDifference(oldClasses, newClasses); - toRemove = digestClassCounts(toRemove, -1); - toAdd = digestClassCounts(toAdd, 1); - - if (toAdd.length === 0) { - $animate.removeClass(element, toRemove); - } else if (toRemove.length === 0) { - $animate.addClass(element, toAdd); - } else { - $animate.setClass(element, toAdd, toRemove); - } - } - - function ngClassWatchAction(newVal) { - if (selector === true || scope.$index % 2 === selector) { - var newClasses = arrayClasses(newVal || []); - if (!oldVal) { - addClasses(newClasses); - } else if (!equals(newVal,oldVal)) { - var oldClasses = arrayClasses(oldVal); - updateClasses(oldClasses, newClasses); - } - } - oldVal = shallowCopy(newVal); - } - } - }; - - function arrayDifference(tokens1, tokens2) { - var values = []; - - outer: - for(var i = 0; i < tokens1.length; i++) { - var token = tokens1[i]; - for(var j = 0; j < tokens2.length; j++) { - if(token == tokens2[j]) continue outer; - } - values.push(token); - } - return values; - } - - function arrayClasses (classVal) { - if (isArray(classVal)) { - return classVal; - } else if (isString(classVal)) { - return classVal.split(' '); - } else if (isObject(classVal)) { - var classes = [], i = 0; - forEach(classVal, function(v, k) { - if (v) { - classes = classes.concat(k.split(' ')); - } - }); - return classes; - } - return classVal; - } - }]; -} - -/** - * @ngdoc directive - * @name ngClass - * @restrict AC - * - * @description - * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding - * an expression that represents all classes to be added. - * - * The directive operates in three different ways, depending on which of three types the expression - * evaluates to: - * - * 1. If the expression evaluates to a string, the string should be one or more space-delimited class - * names. - * - * 2. If the expression evaluates to an array, each element of the array should be a string that is - * one or more space-delimited class names. - * - * 3. If the expression evaluates to an object, then for each key-value pair of the - * object with a truthy value the corresponding key is used as a class name. - * - * The directive won't add duplicate classes if a particular class was already set. - * - * When the expression changes, the previously added classes are removed and only then the - * new classes are added. - * - * @animations - * add - happens just before the class is applied to the element - * remove - happens just before the class is removed from the element - * - * @element ANY - * @param {expression} ngClass {@link guide/expression Expression} to eval. The result - * of the evaluation can be a string representing space delimited class - * names, an array, or a map of class names to boolean values. In the case of a map, the - * names of the properties whose values are truthy will be added as css classes to the - * element. - * - * @example Example that demonstrates basic bindings via ngClass directive. - - -

Map Syntax Example

- deleted (apply "strike" class)
- important (apply "bold" class)
- error (apply "red" class) -
-

Using String Syntax

- -
-

Using Array Syntax

-
-
-
-
- - .strike { - text-decoration: line-through; - } - .bold { - font-weight: bold; - } - .red { - color: red; - } - - - var ps = element.all(by.css('p')); - - it('should let you toggle the class', function() { - - expect(ps.first().getAttribute('class')).not.toMatch(/bold/); - expect(ps.first().getAttribute('class')).not.toMatch(/red/); - - element(by.model('important')).click(); - expect(ps.first().getAttribute('class')).toMatch(/bold/); - - element(by.model('error')).click(); - expect(ps.first().getAttribute('class')).toMatch(/red/); - }); - - it('should let you toggle string example', function() { - expect(ps.get(1).getAttribute('class')).toBe(''); - element(by.model('style')).clear(); - element(by.model('style')).sendKeys('red'); - expect(ps.get(1).getAttribute('class')).toBe('red'); - }); - - it('array example should have 3 classes', function() { - expect(ps.last().getAttribute('class')).toBe(''); - element(by.model('style1')).sendKeys('bold'); - element(by.model('style2')).sendKeys('strike'); - element(by.model('style3')).sendKeys('red'); - expect(ps.last().getAttribute('class')).toBe('bold strike red'); - }); - -
- - ## Animations - - The example below demonstrates how to perform animations using ngClass. - - - - - -
- Sample Text -
- - .base-class { - -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - } - - .base-class.my-class { - color: red; - font-size:3em; - } - - - it('should check ng-class', function() { - expect(element(by.css('.base-class')).getAttribute('class')).not. - toMatch(/my-class/); - - element(by.id('setbtn')).click(); - - expect(element(by.css('.base-class')).getAttribute('class')). - toMatch(/my-class/); - - element(by.id('clearbtn')).click(); - - expect(element(by.css('.base-class')).getAttribute('class')).not. - toMatch(/my-class/); - }); - -
- - - ## ngClass and pre-existing CSS3 Transitions/Animations - The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure. - Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder - any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure - to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and - {@link ngAnimate.$animate#removeclass $animate.removeClass}. - */ -var ngClassDirective = classDirective('', true); - -/** - * @ngdoc directive - * @name ngClassOdd - * @restrict AC - * - * @description - * The `ngClassOdd` and `ngClassEven` directives work exactly as - * {@link ng.directive:ngClass ngClass}, except they work in - * conjunction with `ngRepeat` and take effect only on odd (even) rows. - * - * This directive can be applied only within the scope of an - * {@link ng.directive:ngRepeat ngRepeat}. - * - * @element ANY - * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result - * of the evaluation can be a string representing space delimited class names or an array. - * - * @example - - -
    -
  1. - - {{name}} - -
  2. -
-
- - .odd { - color: red; - } - .even { - color: blue; - } - - - it('should check ng-class-odd and ng-class-even', function() { - expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')). - toMatch(/odd/); - expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')). - toMatch(/even/); - }); - -
- */ -var ngClassOddDirective = classDirective('Odd', 0); - -/** - * @ngdoc directive - * @name ngClassEven - * @restrict AC - * - * @description - * The `ngClassOdd` and `ngClassEven` directives work exactly as - * {@link ng.directive:ngClass ngClass}, except they work in - * conjunction with `ngRepeat` and take effect only on odd (even) rows. - * - * This directive can be applied only within the scope of an - * {@link ng.directive:ngRepeat ngRepeat}. - * - * @element ANY - * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The - * result of the evaluation can be a string representing space delimited class names or an array. - * - * @example - - -
    -
  1. - - {{name}}       - -
  2. -
-
- - .odd { - color: red; - } - .even { - color: blue; - } - - - it('should check ng-class-odd and ng-class-even', function() { - expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')). - toMatch(/odd/); - expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')). - toMatch(/even/); - }); - -
- */ -var ngClassEvenDirective = classDirective('Even', 1); - -/** - * @ngdoc directive - * @name ngCloak - * @restrict AC - * - * @description - * The `ngCloak` directive is used to prevent the Angular html template from being briefly - * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this - * directive to avoid the undesirable flicker effect caused by the html template display. - * - * The directive can be applied to the `` element, but the preferred usage is to apply - * multiple `ngCloak` directives to small portions of the page to permit progressive rendering - * of the browser view. - * - * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and - * `angular.min.js`. - * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). - * - * ```css - * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { - * display: none !important; - * } - * ``` - * - * When this css rule is loaded by the browser, all html elements (including their children) that - * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive - * during the compilation of the template it deletes the `ngCloak` element attribute, making - * the compiled element visible. - * - * For the best result, the `angular.js` script must be loaded in the head section of the html - * document; alternatively, the css rule above must be included in the external stylesheet of the - * application. - * - * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they - * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css - * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below. - * - * @element ANY - * - * @example - - -
{{ 'hello' }}
-
{{ 'hello IE7' }}
-
- - it('should remove the template directive and css class', function() { - expect($('#template1').getAttribute('ng-cloak')). - toBeNull(); - expect($('#template2').getAttribute('ng-cloak')). - toBeNull(); - }); - -
- * - */ -var ngCloakDirective = ngDirective({ - compile: function(element, attr) { - attr.$set('ngCloak', undefined); - element.removeClass('ng-cloak'); - } -}); - -/** - * @ngdoc directive - * @name ngController - * - * @description - * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular - * supports the principles behind the Model-View-Controller design pattern. - * - * MVC components in angular: - * - * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties - * are accessed through bindings. - * * View — The template (HTML with data bindings) that is rendered into the View. - * * Controller — The `ngController` directive specifies a Controller class; the class contains business - * logic behind the application to decorate the scope with functions and values - * - * Note that you can also attach controllers to the DOM by declaring it in a route definition - * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller - * again using `ng-controller` in the template itself. This will cause the controller to be attached - * and executed twice. - * - * @element ANY - * @scope - * @priority 500 - * @param {expression} ngController Name of a globally accessible constructor function or an - * {@link guide/expression expression} that on the current scope evaluates to a - * constructor function. The controller instance can be published into a scope property - * by specifying `as propertyName`. - * - * @example - * Here is a simple form for editing user contact information. Adding, removing, clearing, and - * greeting are methods declared on the controller (see source tab). These methods can - * easily be called from the angular markup. Any changes to the data are automatically reflected - * in the View without the need for a manual update. - * - * Two different declaration styles are included below: - * - * * one binds methods and properties directly onto the controller using `this`: - * `ng-controller="SettingsController1 as settings"` - * * one injects `$scope` into the controller: - * `ng-controller="SettingsController2"` - * - * The second option is more common in the Angular community, and is generally used in boilerplates - * and in this guide. However, there are advantages to binding properties directly to the controller - * and avoiding scope. - * - * * Using `controller as` makes it obvious which controller you are accessing in the template when - * multiple controllers apply to an element. - * * If you are writing your controllers as classes you have easier access to the properties and - * methods, which will appear on the scope, from inside the controller code. - * * Since there is always a `.` in the bindings, you don't have to worry about prototypal - * inheritance masking primitives. - * - * This example demonstrates the `controller as` syntax. - * - * - * - *
- * Name: - * [ greet ]
- * Contact: - *
    - *
  • - * - * - * [ clear - * | X ] - *
  • - *
  • [ add ]
  • - *
- *
- *
- * - * angular.module('controllerAsExample', []) - * .controller('SettingsController1', SettingsController1); - * - * function SettingsController1() { - * this.name = "John Smith"; - * this.contacts = [ - * {type: 'phone', value: '408 555 1212'}, - * {type: 'email', value: 'john.smith@example.org'} ]; - * } - * - * SettingsController1.prototype.greet = function() { - * alert(this.name); - * }; - * - * SettingsController1.prototype.addContact = function() { - * this.contacts.push({type: 'email', value: 'yourname@example.org'}); - * }; - * - * SettingsController1.prototype.removeContact = function(contactToRemove) { - * var index = this.contacts.indexOf(contactToRemove); - * this.contacts.splice(index, 1); - * }; - * - * SettingsController1.prototype.clearContact = function(contact) { - * contact.type = 'phone'; - * contact.value = ''; - * }; - * - * - * it('should check controller as', function() { - * var container = element(by.id('ctrl-as-exmpl')); - * expect(container.element(by.model('settings.name')) - * .getAttribute('value')).toBe('John Smith'); - * - * var firstRepeat = - * container.element(by.repeater('contact in settings.contacts').row(0)); - * var secondRepeat = - * container.element(by.repeater('contact in settings.contacts').row(1)); - * - * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe('408 555 1212'); - * - * expect(secondRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe('john.smith@example.org'); - * - * firstRepeat.element(by.linkText('clear')).click(); - * - * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe(''); - * - * container.element(by.linkText('add')).click(); - * - * expect(container.element(by.repeater('contact in settings.contacts').row(2)) - * .element(by.model('contact.value')) - * .getAttribute('value')) - * .toBe('yourname@example.org'); - * }); - * - *
- * - * This example demonstrates the "attach to `$scope`" style of controller. - * - * - * - *
- * Name: - * [ greet ]
- * Contact: - *
    - *
  • - * - * - * [ clear - * | X ] - *
  • - *
  • [ add ]
  • - *
- *
- *
- * - * angular.module('controllerExample', []) - * .controller('SettingsController2', ['$scope', SettingsController2]); - * - * function SettingsController2($scope) { - * $scope.name = "John Smith"; - * $scope.contacts = [ - * {type:'phone', value:'408 555 1212'}, - * {type:'email', value:'john.smith@example.org'} ]; - * - * $scope.greet = function() { - * alert($scope.name); - * }; - * - * $scope.addContact = function() { - * $scope.contacts.push({type:'email', value:'yourname@example.org'}); - * }; - * - * $scope.removeContact = function(contactToRemove) { - * var index = $scope.contacts.indexOf(contactToRemove); - * $scope.contacts.splice(index, 1); - * }; - * - * $scope.clearContact = function(contact) { - * contact.type = 'phone'; - * contact.value = ''; - * }; - * } - * - * - * it('should check controller', function() { - * var container = element(by.id('ctrl-exmpl')); - * - * expect(container.element(by.model('name')) - * .getAttribute('value')).toBe('John Smith'); - * - * var firstRepeat = - * container.element(by.repeater('contact in contacts').row(0)); - * var secondRepeat = - * container.element(by.repeater('contact in contacts').row(1)); - * - * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe('408 555 1212'); - * expect(secondRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe('john.smith@example.org'); - * - * firstRepeat.element(by.linkText('clear')).click(); - * - * expect(firstRepeat.element(by.model('contact.value')).getAttribute('value')) - * .toBe(''); - * - * container.element(by.linkText('add')).click(); - * - * expect(container.element(by.repeater('contact in contacts').row(2)) - * .element(by.model('contact.value')) - * .getAttribute('value')) - * .toBe('yourname@example.org'); - * }); - * - *
- - */ -var ngControllerDirective = [function() { - return { - scope: true, - controller: '@', - priority: 500 - }; -}]; - -/** - * @ngdoc directive - * @name ngCsp - * - * @element html - * @description - * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support. - * - * This is necessary when developing things like Google Chrome Extensions. - * - * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). - * For Angular to be CSP compatible there are only two things that we need to do differently: - * - * - don't use `Function` constructor to generate optimized value getters - * - don't inject custom stylesheet into the document - * - * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp` - * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will - * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will - * be raised. - * - * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically - * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}). - * To make those directives work in CSP mode, include the `angular-csp.css` manually. - * - * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This - * autodetection however triggers a CSP error to be logged in the console: - * - * ``` - * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of - * script in the following Content Security Policy directive: "default-src 'self'". Note that - * 'script-src' was not explicitly set, so 'default-src' is used as a fallback. - * ``` - * - * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp` - * directive on the root element of the application or on the `angular.js` script tag, whichever - * appears first in the html document. - * - * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.* - * - * @example - * This example shows how to apply the `ngCsp` directive to the `html` tag. - ```html - - - ... - ... - - ``` - */ - -// ngCsp is not implemented as a proper directive any more, because we need it be processed while we -// bootstrap the system (before $parse is instantiated), for this reason we just have -// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc - -/** - * @ngdoc directive - * @name ngClick - * - * @description - * The ngClick directive allows you to specify custom behavior when - * an element is clicked. - * - * @element ANY - * @priority 0 - * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon - * click. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - - count: {{count}} - - - - it('should check ng-click', function() { - expect(element(by.binding('count')).getText()).toMatch('0'); - element(by.css('button')).click(); - expect(element(by.binding('count')).getText()).toMatch('1'); - }); - - - */ -/* - * A collection of directives that allows creation of custom event handlers that are defined as - * angular expressions and are compiled and executed within the current scope. - */ -var ngEventDirectives = {}; - -// For events that might fire synchronously during DOM manipulation -// we need to execute their event handlers asynchronously using $evalAsync, -// so that they are not executed in an inconsistent state. -var forceAsyncEvents = { - 'blur': true, - 'focus': true -}; -forEach( - 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '), - function(eventName) { - var directiveName = directiveNormalize('ng-' + eventName); - ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) { - return { - compile: function($element, attr) { - // We expose the powerful $event object on the scope that provides access to the Window, - // etc. that isn't protected by the fast paths in $parse. We explicitly request better - // checks at the cost of speed since event handler expressions are not executed as - // frequently as regular change detection. - var fn = $parse(attr[directiveName], /* expensiveChecks */ true); - return function ngEventHandler(scope, element) { - element.on(eventName, function(event) { - var callback = function() { - fn(scope, {$event:event}); - }; - if (forceAsyncEvents[eventName] && $rootScope.$$phase) { - scope.$evalAsync(callback); - } else { - scope.$apply(callback); - } - }); - }; - } - }; - }]; - } -); - -/** - * @ngdoc directive - * @name ngDblclick - * - * @description - * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event. - * - * @element ANY - * @priority 0 - * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon - * a dblclick. (The Event object is available as `$event`) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngMousedown - * - * @description - * The ngMousedown directive allows you to specify custom behavior on mousedown event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon - * mousedown. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngMouseup - * - * @description - * Specify custom behavior on mouseup event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon - * mouseup. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - -/** - * @ngdoc directive - * @name ngMouseover - * - * @description - * Specify custom behavior on mouseover event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon - * mouseover. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngMouseenter - * - * @description - * Specify custom behavior on mouseenter event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon - * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngMouseleave - * - * @description - * Specify custom behavior on mouseleave event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon - * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngMousemove - * - * @description - * Specify custom behavior on mousemove event. - * - * @element ANY - * @priority 0 - * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon - * mousemove. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngKeydown - * - * @description - * Specify custom behavior on keydown event. - * - * @element ANY - * @priority 0 - * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon - * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) - * - * @example - - - - key down count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngKeyup - * - * @description - * Specify custom behavior on keyup event. - * - * @element ANY - * @priority 0 - * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon - * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.) - * - * @example - - -

Typing in the input box below updates the key count

- key up count: {{count}} - -

Typing in the input box below updates the keycode

- -

event keyCode: {{ event.keyCode }}

-

event altKey: {{ event.altKey }}

-
-
- */ - - -/** - * @ngdoc directive - * @name ngKeypress - * - * @description - * Specify custom behavior on keypress event. - * - * @element ANY - * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon - * keypress. ({@link guide/expression#-event- Event object is available as `$event`} - * and can be interrogated for keyCode, altKey, etc.) - * - * @example - - - - key press count: {{count}} - - - */ - - -/** - * @ngdoc directive - * @name ngSubmit - * - * @description - * Enables binding angular expressions to onsubmit events. - * - * Additionally it prevents the default action (which for form means sending the request to the - * server and reloading the current page), but only if the form does not contain `action`, - * `data-action`, or `x-action` attributes. - * - *
- * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and - * `ngSubmit` handlers together. See the - * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation} - * for a detailed discussion of when `ngSubmit` may be triggered. - *
- * - * @element form - * @priority 0 - * @param {expression} ngSubmit {@link guide/expression Expression} to eval. - * ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - -
- Enter text and hit enter: - - -
list={{list}}
-
-
- - it('should check ng-submit', function() { - expect(element(by.binding('list')).getText()).toBe('list=[]'); - element(by.css('#submit')).click(); - expect(element(by.binding('list')).getText()).toContain('hello'); - expect(element(by.model('text')).getAttribute('value')).toBe(''); - }); - it('should ignore empty strings', function() { - expect(element(by.binding('list')).getText()).toBe('list=[]'); - element(by.css('#submit')).click(); - element(by.css('#submit')).click(); - expect(element(by.binding('list')).getText()).toContain('hello'); - }); - -
- */ - -/** - * @ngdoc directive - * @name ngFocus - * - * @description - * Specify custom behavior on focus event. - * - * Note: As the `focus` event is executed synchronously when calling `input.focus()` - * AngularJS executes the expression using `scope.$evalAsync` if the event is fired - * during an `$apply` to ensure a consistent state. - * - * @element window, input, select, textarea, a - * @priority 0 - * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon - * focus. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - * See {@link ng.directive:ngClick ngClick} - */ - -/** - * @ngdoc directive - * @name ngBlur - * - * @description - * Specify custom behavior on blur event. - * - * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when - * an element has lost focus. - * - * Note: As the `blur` event is executed synchronously also during DOM manipulations - * (e.g. removing a focussed input), - * AngularJS executes the expression using `scope.$evalAsync` if the event is fired - * during an `$apply` to ensure a consistent state. - * - * @element window, input, select, textarea, a - * @priority 0 - * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon - * blur. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - * See {@link ng.directive:ngClick ngClick} - */ - -/** - * @ngdoc directive - * @name ngCopy - * - * @description - * Specify custom behavior on copy event. - * - * @element window, input, select, textarea, a - * @priority 0 - * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon - * copy. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - copied: {{copied}} - - - */ - -/** - * @ngdoc directive - * @name ngCut - * - * @description - * Specify custom behavior on cut event. - * - * @element window, input, select, textarea, a - * @priority 0 - * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon - * cut. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - cut: {{cut}} - - - */ - -/** - * @ngdoc directive - * @name ngPaste - * - * @description - * Specify custom behavior on paste event. - * - * @element window, input, select, textarea, a - * @priority 0 - * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon - * paste. ({@link guide/expression#-event- Event object is available as `$event`}) - * - * @example - - - - pasted: {{paste}} - - - */ - -/** - * @ngdoc directive - * @name ngIf - * @restrict A - * - * @description - * The `ngIf` directive removes or recreates a portion of the DOM tree based on an - * {expression}. If the expression assigned to `ngIf` evaluates to a false - * value then the element is removed from the DOM, otherwise a clone of the - * element is reinserted into the DOM. - * - * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the - * element in the DOM rather than changing its visibility via the `display` css property. A common - * case when this difference is significant is when using css selectors that rely on an element's - * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes. - * - * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope - * is created when the element is restored. The scope created within `ngIf` inherits from - * its parent scope using - * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance). - * An important implication of this is if `ngModel` is used within `ngIf` to bind to - * a javascript primitive defined in the parent scope. In this case any modifications made to the - * variable within the child scope will override (hide) the value in the parent scope. - * - * Also, `ngIf` recreates elements using their compiled state. An example of this behavior - * is if an element's class attribute is directly modified after it's compiled, using something like - * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element - * the added class will be lost because the original compiled state is used to regenerate the element. - * - * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter` - * and `leave` effects. - * - * @animations - * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container - * leave - happens just before the `ngIf` contents are removed from the DOM - * - * @element ANY - * @scope - * @priority 600 - * @param {expression} ngIf If the {@link guide/expression expression} is falsy then - * the element is removed from the DOM tree. If it is truthy a copy of the compiled - * element is added to the DOM tree. - * - * @example - - - Click me:
- Show when checked: - - I'm removed when the checkbox is unchecked. - -
- - .animate-if { - background:white; - border:1px solid black; - padding:10px; - } - - .animate-if.ng-enter, .animate-if.ng-leave { - -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - } - - .animate-if.ng-enter, - .animate-if.ng-leave.ng-leave-active { - opacity:0; - } - - .animate-if.ng-leave, - .animate-if.ng-enter.ng-enter-active { - opacity:1; - } - -
- */ -var ngIfDirective = ['$animate', function($animate) { - return { - transclude: 'element', - priority: 600, - terminal: true, - restrict: 'A', - $$tlb: true, - link: function ($scope, $element, $attr, ctrl, $transclude) { - var block, childScope, previousElements; - $scope.$watch($attr.ngIf, function ngIfWatchAction(value) { - - if (toBoolean(value)) { - if (!childScope) { - childScope = $scope.$new(); - $transclude(childScope, function (clone) { - clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' '); - // Note: We only need the first/last node of the cloned nodes. - // However, we need to keep the reference to the jqlite wrapper as it might be changed later - // by a directive with templateUrl when its template arrives. - block = { - clone: clone - }; - $animate.enter(clone, $element.parent(), $element); - }); - } - } else { - if(previousElements) { - previousElements.remove(); - previousElements = null; - } - if(childScope) { - childScope.$destroy(); - childScope = null; - } - if(block) { - previousElements = getBlockElements(block.clone); - $animate.leave(previousElements, function() { - previousElements = null; - }); - block = null; - } - } - }); - } - }; -}]; - -/** - * @ngdoc directive - * @name ngInclude - * @restrict ECA - * - * @description - * Fetches, compiles and includes an external HTML fragment. - * - * By default, the template URL is restricted to the same domain and protocol as the - * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl - * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols - * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or - * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link - * ng.$sce Strict Contextual Escaping}. - * - * In addition, the browser's - * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) - * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/) - * policy may further restrict whether the template is successfully loaded. - * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://` - * access on some browsers. - * - * @animations - * enter - animation is used to bring new content into the browser. - * leave - animation is used to animate existing content away. - * - * The enter and leave animation occur concurrently. - * - * @scope - * @priority 400 - * - * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant, - * make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`. - * @param {string=} onload Expression to evaluate when a new partial is loaded. - * - * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll - * $anchorScroll} to scroll the viewport after the content is loaded. - * - * - If the attribute is not set, disable scrolling. - * - If the attribute is set without value, enable scrolling. - * - Otherwise enable scrolling only if the expression evaluates to truthy value. - * - * @example - - -
- - url of the template: {{template.url}} -
-
-
-
-
-
- - angular.module('includeExample', ['ngAnimate']) - .controller('ExampleController', ['$scope', function($scope) { - $scope.templates = - [ { name: 'template1.html', url: 'template1.html'}, - { name: 'template2.html', url: 'template2.html'} ]; - $scope.template = $scope.templates[0]; - }]); - - - Content of template1.html - - - Content of template2.html - - - .slide-animate-container { - position:relative; - background:white; - border:1px solid black; - height:40px; - overflow:hidden; - } - - .slide-animate { - padding:10px; - } - - .slide-animate.ng-enter, .slide-animate.ng-leave { - -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - - position:absolute; - top:0; - left:0; - right:0; - bottom:0; - display:block; - padding:10px; - } - - .slide-animate.ng-enter { - top:-50px; - } - .slide-animate.ng-enter.ng-enter-active { - top:0; - } - - .slide-animate.ng-leave { - top:0; - } - .slide-animate.ng-leave.ng-leave-active { - top:50px; - } - - - var templateSelect = element(by.model('template')); - var includeElem = element(by.css('[ng-include]')); - - it('should load template1.html', function() { - expect(includeElem.getText()).toMatch(/Content of template1.html/); - }); - - it('should load template2.html', function() { - if (browser.params.browser == 'firefox') { - // Firefox can't handle using selects - // See https://github.com/angular/protractor/issues/480 - return; - } - templateSelect.click(); - templateSelect.all(by.css('option')).get(2).click(); - expect(includeElem.getText()).toMatch(/Content of template2.html/); - }); - - it('should change to blank', function() { - if (browser.params.browser == 'firefox') { - // Firefox can't handle using selects - return; - } - templateSelect.click(); - templateSelect.all(by.css('option')).get(0).click(); - expect(includeElem.isPresent()).toBe(false); - }); - -
- */ - - -/** - * @ngdoc event - * @name ngInclude#$includeContentRequested - * @eventType emit on the scope ngInclude was declared in - * @description - * Emitted every time the ngInclude content is requested. - */ - - -/** - * @ngdoc event - * @name ngInclude#$includeContentLoaded - * @eventType emit on the current ngInclude scope - * @description - * Emitted every time the ngInclude content is reloaded. - */ -var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce', - function($http, $templateCache, $anchorScroll, $animate, $sce) { - return { - restrict: 'ECA', - priority: 400, - terminal: true, - transclude: 'element', - controller: angular.noop, - compile: function(element, attr) { - var srcExp = attr.ngInclude || attr.src, - onloadExp = attr.onload || '', - autoScrollExp = attr.autoscroll; - - return function(scope, $element, $attr, ctrl, $transclude) { - var changeCounter = 0, - currentScope, - previousElement, - currentElement; - - var cleanupLastIncludeContent = function() { - if(previousElement) { - previousElement.remove(); - previousElement = null; - } - if(currentScope) { - currentScope.$destroy(); - currentScope = null; - } - if(currentElement) { - $animate.leave(currentElement, function() { - previousElement = null; - }); - previousElement = currentElement; - currentElement = null; - } - }; - - scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) { - var afterAnimation = function() { - if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) { - $anchorScroll(); - } - }; - var thisChangeId = ++changeCounter; - - if (src) { - $http.get(src, {cache: $templateCache}).success(function(response) { - if (thisChangeId !== changeCounter) return; - var newScope = scope.$new(); - ctrl.template = response; - - // Note: This will also link all children of ng-include that were contained in the original - // html. If that content contains controllers, ... they could pollute/change the scope. - // However, using ng-include on an element with additional content does not make sense... - // Note: We can't remove them in the cloneAttchFn of $transclude as that - // function is called before linking the content, which would apply child - // directives to non existing elements. - var clone = $transclude(newScope, function(clone) { - cleanupLastIncludeContent(); - $animate.enter(clone, null, $element, afterAnimation); - }); - - currentScope = newScope; - currentElement = clone; - - currentScope.$emit('$includeContentLoaded'); - scope.$eval(onloadExp); - }).error(function() { - if (thisChangeId === changeCounter) cleanupLastIncludeContent(); - }); - scope.$emit('$includeContentRequested'); - } else { - cleanupLastIncludeContent(); - ctrl.template = null; - } - }); - }; - } - }; -}]; - -// This directive is called during the $transclude call of the first `ngInclude` directive. -// It will replace and compile the content of the element with the loaded template. -// We need this directive so that the element content is already filled when -// the link function of another directive on the same element as ngInclude -// is called. -var ngIncludeFillContentDirective = ['$compile', - function($compile) { - return { - restrict: 'ECA', - priority: -400, - require: 'ngInclude', - link: function(scope, $element, $attr, ctrl) { - $element.html(ctrl.template); - $compile($element.contents())(scope); - } - }; - }]; - -/** - * @ngdoc directive - * @name ngInit - * @restrict AC - * - * @description - * The `ngInit` directive allows you to evaluate an expression in the - * current scope. - * - *
- * The only appropriate use of `ngInit` is for aliasing special properties of - * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you - * should use {@link guide/controller controllers} rather than `ngInit` - * to initialize values on a scope. - *
- *
- * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make - * sure you have parenthesis for correct precedence: - *
- *   
- *
- *
- * - * @priority 450 - * - * @element ANY - * @param {expression} ngInit {@link guide/expression Expression} to eval. - * - * @example - - - -
-
-
- list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}}; -
-
-
-
- - it('should alias index positions', function() { - var elements = element.all(by.css('.example-init')); - expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;'); - expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;'); - expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;'); - expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;'); - }); - -
- */ -var ngInitDirective = ngDirective({ - priority: 450, - compile: function() { - return { - pre: function(scope, element, attrs) { - scope.$eval(attrs.ngInit); - } - }; - } -}); - -/** - * @ngdoc directive - * @name ngNonBindable - * @restrict AC - * @priority 1000 - * - * @description - * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current - * DOM element. This is useful if the element contains what appears to be Angular directives and - * bindings but which should be ignored by Angular. This could be the case if you have a site that - * displays snippets of code, for instance. - * - * @element ANY - * - * @example - * In this example there are two locations where a simple interpolation binding (`{{}}`) is present, - * but the one wrapped in `ngNonBindable` is left alone. - * - * @example - - -
Normal: {{1 + 2}}
-
Ignored: {{1 + 2}}
-
- - it('should check ng-non-bindable', function() { - expect(element(by.binding('1 + 2')).getText()).toContain('3'); - expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/); - }); - -
- */ -var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 }); - -/** - * @ngdoc directive - * @name ngPluralize - * @restrict EA - * - * @description - * `ngPluralize` is a directive that displays messages according to en-US localization rules. - * These rules are bundled with angular.js, but can be overridden - * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive - * by specifying the mappings between - * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) - * and the strings to be displayed. - * - * # Plural categories and explicit number rules - * There are two - * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html) - * in Angular's default en-US locale: "one" and "other". - * - * While a plural category may match many numbers (for example, in en-US locale, "other" can match - * any number that is not 1), an explicit number rule can only match one number. For example, the - * explicit number rule for "3" matches the number 3. There are examples of plural categories - * and explicit number rules throughout the rest of this documentation. - * - * # Configuring ngPluralize - * You configure ngPluralize by providing 2 attributes: `count` and `when`. - * You can also provide an optional attribute, `offset`. - * - * The value of the `count` attribute can be either a string or an {@link guide/expression - * Angular expression}; these are evaluated on the current scope for its bound value. - * - * The `when` attribute specifies the mappings between plural categories and the actual - * string to be displayed. The value of the attribute should be a JSON object. - * - * The following example shows how to configure ngPluralize: - * - * ```html - * - * - *``` - * - * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not - * specify this rule, 0 would be matched to the "other" category and "0 people are viewing" - * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for - * other numbers, for example 12, so that instead of showing "12 people are viewing", you can - * show "a dozen people are viewing". - * - * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted - * into pluralized strings. In the previous example, Angular will replace `{}` with - * `{{personCount}}`. The closed braces `{}` is a placeholder - * for {{numberExpression}}. - * - * # Configuring ngPluralize with offset - * The `offset` attribute allows further customization of pluralized text, which can result in - * a better user experience. For example, instead of the message "4 people are viewing this document", - * you might display "John, Kate and 2 others are viewing this document". - * The offset attribute allows you to offset a number by any desired value. - * Let's take a look at an example: - * - * ```html - * - * - * ``` - * - * Notice that we are still using two plural categories(one, other), but we added - * three explicit number rules 0, 1 and 2. - * When one person, perhaps John, views the document, "John is viewing" will be shown. - * When three people view the document, no explicit number rule is found, so - * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category. - * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing" - * is shown. - * - * Note that when you specify offsets, you must provide explicit number rules for - * numbers from 0 up to and including the offset. If you use an offset of 3, for example, - * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for - * plural categories "one" and "other". - * - * @param {string|expression} count The variable to be bound to. - * @param {string} when The mapping between plural category to its corresponding strings. - * @param {number=} offset Offset to deduct from the total number. - * - * @example - - - -
- Person 1:
- Person 2:
- Number of People:
- - - Without Offset: - -
- - - With Offset(2): - - -
-
- - it('should show correct pluralized string', function() { - var withoutOffset = element.all(by.css('ng-pluralize')).get(0); - var withOffset = element.all(by.css('ng-pluralize')).get(1); - var countInput = element(by.model('personCount')); - - expect(withoutOffset.getText()).toEqual('1 person is viewing.'); - expect(withOffset.getText()).toEqual('Igor is viewing.'); - - countInput.clear(); - countInput.sendKeys('0'); - - expect(withoutOffset.getText()).toEqual('Nobody is viewing.'); - expect(withOffset.getText()).toEqual('Nobody is viewing.'); - - countInput.clear(); - countInput.sendKeys('2'); - - expect(withoutOffset.getText()).toEqual('2 people are viewing.'); - expect(withOffset.getText()).toEqual('Igor and Misko are viewing.'); - - countInput.clear(); - countInput.sendKeys('3'); - - expect(withoutOffset.getText()).toEqual('3 people are viewing.'); - expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.'); - - countInput.clear(); - countInput.sendKeys('4'); - - expect(withoutOffset.getText()).toEqual('4 people are viewing.'); - expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.'); - }); - it('should show data-bound names', function() { - var withOffset = element.all(by.css('ng-pluralize')).get(1); - var personCount = element(by.model('personCount')); - var person1 = element(by.model('person1')); - var person2 = element(by.model('person2')); - personCount.clear(); - personCount.sendKeys('4'); - person1.clear(); - person1.sendKeys('Di'); - person2.clear(); - person2.sendKeys('Vojta'); - expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.'); - }); - -
- */ -var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) { - var BRACE = /{}/g; - return { - restrict: 'EA', - link: function(scope, element, attr) { - var numberExp = attr.count, - whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs - offset = attr.offset || 0, - whens = scope.$eval(whenExp) || {}, - whensExpFns = {}, - startSymbol = $interpolate.startSymbol(), - endSymbol = $interpolate.endSymbol(), - isWhen = /^when(Minus)?(.+)$/; - - forEach(attr, function(expression, attributeName) { - if (isWhen.test(attributeName)) { - whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] = - element.attr(attr.$attr[attributeName]); - } - }); - forEach(whens, function(expression, key) { - whensExpFns[key] = - $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' + - offset + endSymbol)); - }); - - scope.$watch(function ngPluralizeWatch() { - var value = parseFloat(scope.$eval(numberExp)); - - if (!isNaN(value)) { - //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, - //check it against pluralization rules in $locale service - if (!(value in whens)) value = $locale.pluralCat(value - offset); - return whensExpFns[value](scope, element, true); - } else { - return ''; - } - }, function ngPluralizeWatchAction(newVal) { - element.text(newVal); - }); - } - }; -}]; - -/** - * @ngdoc directive - * @name ngRepeat - * - * @description - * The `ngRepeat` directive instantiates a template once per item from a collection. Each template - * instance gets its own scope, where the given loop variable is set to the current collection item, - * and `$index` is set to the item index or key. - * - * Special properties are exposed on the local scope of each template instance, including: - * - * | Variable | Type | Details | - * |-----------|-----------------|-----------------------------------------------------------------------------| - * | `$index` | {@type number} | iterator offset of the repeated element (0..length-1) | - * | `$first` | {@type boolean} | true if the repeated element is first in the iterator. | - * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. | - * | `$last` | {@type boolean} | true if the repeated element is last in the iterator. | - * | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). | - * | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). | - * - * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}. - * This may be useful when, for instance, nesting ngRepeats. - * - * # Special repeat start and end points - * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending - * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively. - * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on) - * up to and including the ending HTML tag where **ng-repeat-end** is placed. - * - * The example below makes use of this feature: - * ```html - *
- * Header {{ item }} - *
- *
- * Body {{ item }} - *
- *
- * Footer {{ item }} - *
- * ``` - * - * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to: - * ```html - *
- * Header A - *
- *
- * Body A - *
- *
- * Footer A - *
- *
- * Header B - *
- *
- * Body B - *
- *
- * Footer B - *
- * ``` - * - * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such - * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**). - * - * @animations - * **.enter** - when a new item is added to the list or when an item is revealed after a filter - * - * **.leave** - when an item is removed from the list or when an item is filtered out - * - * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered - * - * @element ANY - * @scope - * @priority 1000 - * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These - * formats are currently supported: - * - * * `variable in expression` – where variable is the user defined loop variable and `expression` - * is a scope expression giving the collection to enumerate. - * - * For example: `album in artist.albums`. - * - * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers, - * and `expression` is the scope expression giving the collection to enumerate. - * - * For example: `(name, age) in {'adam':10, 'amalie':12}`. - * - * * `variable in expression track by tracking_expression` – You can also provide an optional tracking function - * which can be used to associate the objects in the collection with the DOM elements. If no tracking function - * is specified the ng-repeat associates elements by identity in the collection. It is an error to have - * more than one tracking function to resolve to the same key. (This would mean that two distinct objects are - * mapped to the same DOM element, which is not possible.) Filters should be applied to the expression, - * before specifying a tracking expression. - * - * For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements - * will be associated by item identity in the array. - * - * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique - * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements - * with the corresponding item in the array by identity. Moving the same object in array would move the DOM - * element in the same way in the DOM. - * - * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this - * case the object identity does not matter. Two objects are considered equivalent as long as their `id` - * property is same. - * - * For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter - * to items in conjunction with a tracking expression. - * - * @example - * This example initializes the scope to a list of names and - * then uses `ngRepeat` to display every person: - - -
- I have {{friends.length}} friends. They are: - -
    -
  • - [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old. -
  • -
-
-
- - .example-animate-container { - background:white; - border:1px solid black; - list-style:none; - margin:0; - padding:0 10px; - } - - .animate-repeat { - line-height:40px; - list-style:none; - box-sizing:border-box; - } - - .animate-repeat.ng-move, - .animate-repeat.ng-enter, - .animate-repeat.ng-leave { - -webkit-transition:all linear 0.5s; - transition:all linear 0.5s; - } - - .animate-repeat.ng-leave.ng-leave-active, - .animate-repeat.ng-move, - .animate-repeat.ng-enter { - opacity:0; - max-height:0; - } - - .animate-repeat.ng-leave, - .animate-repeat.ng-move.ng-move-active, - .animate-repeat.ng-enter.ng-enter-active { - opacity:1; - max-height:40px; - } - - - var friends = element.all(by.repeater('friend in friends')); - - it('should render initial data set', function() { - expect(friends.count()).toBe(10); - expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.'); - expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.'); - expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.'); - expect(element(by.binding('friends.length')).getText()) - .toMatch("I have 10 friends. They are:"); - }); - - it('should update repeater when filter predicate changes', function() { - expect(friends.count()).toBe(10); - - element(by.model('q')).sendKeys('ma'); - - expect(friends.count()).toBe(2); - expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.'); - expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.'); - }); - -
- */ -var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) { - var NG_REMOVED = '$$NG_REMOVED'; - var ngRepeatMinErr = minErr('ngRepeat'); - return { - transclude: 'element', - priority: 1000, - terminal: true, - $$tlb: true, - link: function($scope, $element, $attr, ctrl, $transclude){ - var expression = $attr.ngRepeat; - var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/), - trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn, - lhs, rhs, valueIdentifier, keyIdentifier, - hashFnLocals = {$id: hashKey}; - - if (!match) { - throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", - expression); - } - - lhs = match[1]; - rhs = match[2]; - trackByExp = match[3]; - - if (trackByExp) { - trackByExpGetter = $parse(trackByExp); - trackByIdExpFn = function(key, value, index) { - // assign key, value, and $index to the locals so that they can be used in hash functions - if (keyIdentifier) hashFnLocals[keyIdentifier] = key; - hashFnLocals[valueIdentifier] = value; - hashFnLocals.$index = index; - return trackByExpGetter($scope, hashFnLocals); - }; - } else { - trackByIdArrayFn = function(key, value) { - return hashKey(value); - }; - trackByIdObjFn = function(key) { - return key; - }; - } - - match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/); - if (!match) { - throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", - lhs); - } - valueIdentifier = match[3] || match[1]; - keyIdentifier = match[2]; - - // Store a list of elements from previous run. This is a hash where key is the item from the - // iterator, and the value is objects with following properties. - // - scope: bound scope - // - element: previous element. - // - index: position - var lastBlockMap = {}; - - //watch props - $scope.$watchCollection(rhs, function ngRepeatAction(collection){ - var index, length, - previousNode = $element[0], // current position of the node - nextNode, - // Same as lastBlockMap but it has the current state. It will become the - // lastBlockMap on the next iteration. - nextBlockMap = {}, - arrayLength, - childScope, - key, value, // key/value of iteration - trackById, - trackByIdFn, - collectionKeys, - block, // last object information {scope, element, id} - nextBlockOrder = [], - elementsToRemove; - - - if (isArrayLike(collection)) { - collectionKeys = collection; - trackByIdFn = trackByIdExpFn || trackByIdArrayFn; - } else { - trackByIdFn = trackByIdExpFn || trackByIdObjFn; - // if object, extract keys, sort them and use to determine order of iteration over obj props - collectionKeys = []; - for (key in collection) { - if (collection.hasOwnProperty(key) && key.charAt(0) != '$') { - collectionKeys.push(key); - } - } - collectionKeys.sort(); - } - - arrayLength = collectionKeys.length; - - // locate existing items - length = nextBlockOrder.length = collectionKeys.length; - for(index = 0; index < length; index++) { - key = (collection === collectionKeys) ? index : collectionKeys[index]; - value = collection[key]; - trackById = trackByIdFn(key, value, index); - assertNotHasOwnProperty(trackById, '`track by` id'); - if(lastBlockMap.hasOwnProperty(trackById)) { - block = lastBlockMap[trackById]; - delete lastBlockMap[trackById]; - nextBlockMap[trackById] = block; - nextBlockOrder[index] = block; - } else if (nextBlockMap.hasOwnProperty(trackById)) { - // restore lastBlockMap - forEach(nextBlockOrder, function(block) { - if (block && block.scope) lastBlockMap[block.id] = block; - }); - // This is a duplicate and we need to throw an error - throw ngRepeatMinErr('dupes', - "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}", - expression, trackById, toJson(value)); - } else { - // new never before seen block - nextBlockOrder[index] = { id: trackById }; - nextBlockMap[trackById] = false; - } - } - - // remove existing items - for (key in lastBlockMap) { - // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn - if (lastBlockMap.hasOwnProperty(key)) { - block = lastBlockMap[key]; - elementsToRemove = getBlockElements(block.clone); - $animate.leave(elementsToRemove); - forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; }); - block.scope.$destroy(); - } - } - - // we are not using forEach for perf reasons (trying to avoid #call) - for (index = 0, length = collectionKeys.length; index < length; index++) { - key = (collection === collectionKeys) ? index : collectionKeys[index]; - value = collection[key]; - block = nextBlockOrder[index]; - if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]); - - if (block.scope) { - // if we have already seen this object, then we need to reuse the - // associated scope/element - childScope = block.scope; - - nextNode = previousNode; - do { - nextNode = nextNode.nextSibling; - } while(nextNode && nextNode[NG_REMOVED]); - - if (getBlockStart(block) != nextNode) { - // existing item which got moved - $animate.move(getBlockElements(block.clone), null, jqLite(previousNode)); - } - previousNode = getBlockEnd(block); - } else { - // new item which we don't know about - childScope = $scope.$new(); - } - - childScope[valueIdentifier] = value; - if (keyIdentifier) childScope[keyIdentifier] = key; - childScope.$index = index; - childScope.$first = (index === 0); - childScope.$last = (index === (arrayLength - 1)); - childScope.$middle = !(childScope.$first || childScope.$last); - // jshint bitwise: false - childScope.$odd = !(childScope.$even = (index&1) === 0); - // jshint bitwise: true - - if (!block.scope) { - $transclude(childScope, function(clone) { - clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' '); - $animate.enter(clone, null, jqLite(previousNode)); - previousNode = clone; - block.scope = childScope; - // Note: We only need the first/last node of the cloned nodes. - // However, we need to keep the reference to the jqlite wrapper as it might be changed later - // by a directive with templateUrl when its template arrives. - block.clone = clone; - nextBlockMap[block.id] = block; - }); - } - } - lastBlockMap = nextBlockMap; - }); - } - }; - - function getBlockStart(block) { - return block.clone[0]; - } - - function getBlockEnd(block) { - return block.clone[block.clone.length - 1]; - } -}]; - -/** - * @ngdoc directive - * @name ngShow - * - * @description - * The `ngShow` directive shows or hides the given HTML element based on the expression - * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding - * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined - * in AngularJS and sets the display style to none (using an !important flag). - * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). - * - * ```html - * - *
- * - * - *
- * ``` - * - * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute - * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed - * from the element causing the element not to appear hidden. - * - *
- * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):
- * "f" / "0" / "false" / "no" / "n" / "[]" - *
- * - * ## Why is !important used? - * - * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector - * can be easily overridden by heavier selectors. For example, something as simple - * as changing the display style on a HTML list item would make hidden elements appear visible. - * This also becomes a bigger issue when dealing with CSS frameworks. - * - * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector - * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the - * styling to change how to hide an element then it is just a matter of using !important in their own CSS code. - * - * ### Overriding `.ng-hide` - * - * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change - * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide` - * class in CSS: - * - * ```css - * .ng-hide { - * //this is just another form of hiding an element - * display:block!important; - * position:absolute; - * top:-9999px; - * left:-9999px; - * } - * ``` - * - * By default you don't need to override in CSS anything and the animations will work around the display style. - * - * ## A note about animations with `ngShow` - * - * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression - * is true and false. This system works like the animation system present with ngClass except that - * you must also include the !important flag to override the display property - * so that you can perform an animation when the element is hidden during the time of the animation. - * - * ```css - * // - * //a working example can be found at the bottom of this page - * // - * .my-element.ng-hide-add, .my-element.ng-hide-remove { - * transition:0.5s linear all; - * } - * - * .my-element.ng-hide-add { ... } - * .my-element.ng-hide-add.ng-hide-add-active { ... } - * .my-element.ng-hide-remove { ... } - * .my-element.ng-hide-remove.ng-hide-remove-active { ... } - * ``` - * - * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display - * property to block during animation states--ngAnimate will handle the style toggling automatically for you. - * - * @animations - * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible - * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden - * - * @element ANY - * @param {expression} ngShow If the {@link guide/expression expression} is truthy - * then the element is shown or hidden respectively. - * - * @example - - - Click me:
-
- Show: -
- I show up when your checkbox is checked. -
-
-
- Hide: -
- I hide when your checkbox is checked. -
-
-
- - @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css); - - - .animate-show { - -webkit-transition:all linear 0.5s; - transition:all linear 0.5s; - line-height:20px; - opacity:1; - padding:10px; - border:1px solid black; - background:white; - } - - .animate-show.ng-hide { - line-height:0; - opacity:0; - padding:0 10px; - } - - .check-element { - padding:10px; - border:1px solid black; - background:white; - } - - - var thumbsUp = element(by.css('span.glyphicon-thumbs-up')); - var thumbsDown = element(by.css('span.glyphicon-thumbs-down')); - - it('should check ng-show / ng-hide', function() { - expect(thumbsUp.isDisplayed()).toBeFalsy(); - expect(thumbsDown.isDisplayed()).toBeTruthy(); - - element(by.model('checked')).click(); - - expect(thumbsUp.isDisplayed()).toBeTruthy(); - expect(thumbsDown.isDisplayed()).toBeFalsy(); - }); - -
- */ -var ngShowDirective = ['$animate', function($animate) { - return function(scope, element, attr) { - scope.$watch(attr.ngShow, function ngShowWatchAction(value){ - $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide'); - }); - }; -}]; - - -/** - * @ngdoc directive - * @name ngHide - * - * @description - * The `ngHide` directive shows or hides the given HTML element based on the expression - * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding - * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined - * in AngularJS and sets the display style to none (using an !important flag). - * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}). - * - * ```html - * - *
- * - * - *
- * ``` - * - * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute - * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed - * from the element causing the element not to appear hidden. - * - *
- * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):
- * "f" / "0" / "false" / "no" / "n" / "[]" - *
- * - * ## Why is !important used? - * - * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector - * can be easily overridden by heavier selectors. For example, something as simple - * as changing the display style on a HTML list item would make hidden elements appear visible. - * This also becomes a bigger issue when dealing with CSS frameworks. - * - * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector - * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the - * styling to change how to hide an element then it is just a matter of using !important in their own CSS code. - * - * ### Overriding `.ng-hide` - * - * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change - * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide` - * class in CSS: - * - * ```css - * .ng-hide { - * //this is just another form of hiding an element - * display:block!important; - * position:absolute; - * top:-9999px; - * left:-9999px; - * } - * ``` - * - * By default you don't need to override in CSS anything and the animations will work around the display style. - * - * ## A note about animations with `ngHide` - * - * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression - * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide` - * CSS class is added and removed for you instead of your own CSS class. - * - * ```css - * // - * //a working example can be found at the bottom of this page - * // - * .my-element.ng-hide-add, .my-element.ng-hide-remove { - * transition:0.5s linear all; - * } - * - * .my-element.ng-hide-add { ... } - * .my-element.ng-hide-add.ng-hide-add-active { ... } - * .my-element.ng-hide-remove { ... } - * .my-element.ng-hide-remove.ng-hide-remove-active { ... } - * ``` - * - * Keep in mind that, as of AngularJS version 1.2.17 (and 1.3.0-beta.11), there is no need to change the display - * property to block during animation states--ngAnimate will handle the style toggling automatically for you. - * - * @animations - * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden - * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible - * - * @element ANY - * @param {expression} ngHide If the {@link guide/expression expression} is truthy then - * the element is shown or hidden respectively. - * - * @example - - - Click me:
-
- Show: -
- I show up when your checkbox is checked. -
-
-
- Hide: -
- I hide when your checkbox is checked. -
-
-
- - @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css); - - - .animate-hide { - -webkit-transition:all linear 0.5s; - transition:all linear 0.5s; - line-height:20px; - opacity:1; - padding:10px; - border:1px solid black; - background:white; - } - - .animate-hide.ng-hide { - line-height:0; - opacity:0; - padding:0 10px; - } - - .check-element { - padding:10px; - border:1px solid black; - background:white; - } - - - var thumbsUp = element(by.css('span.glyphicon-thumbs-up')); - var thumbsDown = element(by.css('span.glyphicon-thumbs-down')); - - it('should check ng-show / ng-hide', function() { - expect(thumbsUp.isDisplayed()).toBeFalsy(); - expect(thumbsDown.isDisplayed()).toBeTruthy(); - - element(by.model('checked')).click(); - - expect(thumbsUp.isDisplayed()).toBeTruthy(); - expect(thumbsDown.isDisplayed()).toBeFalsy(); - }); - -
- */ -var ngHideDirective = ['$animate', function($animate) { - return function(scope, element, attr) { - scope.$watch(attr.ngHide, function ngHideWatchAction(value){ - $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide'); - }); - }; -}]; - -/** - * @ngdoc directive - * @name ngStyle - * @restrict AC - * - * @description - * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally. - * - * @element ANY - * @param {expression} ngStyle - * - * {@link guide/expression Expression} which evals to an - * object whose keys are CSS style names and values are corresponding values for those CSS - * keys. - * - * Since some CSS style names are not valid keys for an object, they must be quoted. - * See the 'background-color' style in the example below. - * - * @example - - - - - -
- Sample Text -
myStyle={{myStyle}}
-
- - span { - color: black; - } - - - var colorSpan = element(by.css('span')); - - it('should check ng-style', function() { - expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)'); - element(by.css('input[value=\'set color\']')).click(); - expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)'); - element(by.css('input[value=clear]')).click(); - expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)'); - }); - -
- */ -var ngStyleDirective = ngDirective(function(scope, element, attr) { - scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) { - if (oldStyles && (newStyles !== oldStyles)) { - forEach(oldStyles, function(val, style) { element.css(style, '');}); - } - if (newStyles) element.css(newStyles); - }, true); -}); - -/** - * @ngdoc directive - * @name ngSwitch - * @restrict EA - * - * @description - * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression. - * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location - * as specified in the template. - * - * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it - * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element - * matches the value obtained from the evaluated expression. In other words, you define a container element - * (where you place the directive), place an expression on the **`on="..."` attribute** - * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place - * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on - * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default - * attribute is displayed. - * - *
- * Be aware that the attribute values to match against cannot be expressions. They are interpreted - * as literal string values to match against. - * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the - * value of the expression `$scope.someVal`. - *
- - * @animations - * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container - * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM - * - * @usage - * - * ``` - * - * ... - * ... - * ... - * - * ``` - * - * - * @scope - * @priority 800 - * @param {*} ngSwitch|on expression to match against ng-switch-when. - * On child elements add: - * - * * `ngSwitchWhen`: the case statement to match against. If match then this - * case will be displayed. If the same match appears multiple times, all the - * elements will be displayed. - * * `ngSwitchDefault`: the default case when no other case match. If there - * are multiple default cases, all of them will be displayed when no other - * case match. - * - * - * @example - - -
- - selection={{selection}} -
-
-
Settings Div
-
Home Span
-
default
-
-
-
- - angular.module('switchExample', ['ngAnimate']) - .controller('ExampleController', ['$scope', function($scope) { - $scope.items = ['settings', 'home', 'other']; - $scope.selection = $scope.items[0]; - }]); - - - .animate-switch-container { - position:relative; - background:white; - border:1px solid black; - height:40px; - overflow:hidden; - } - - .animate-switch { - padding:10px; - } - - .animate-switch.ng-animate { - -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s; - - position:absolute; - top:0; - left:0; - right:0; - bottom:0; - } - - .animate-switch.ng-leave.ng-leave-active, - .animate-switch.ng-enter { - top:-50px; - } - .animate-switch.ng-leave, - .animate-switch.ng-enter.ng-enter-active { - top:0; - } - - - var switchElem = element(by.css('[ng-switch]')); - var select = element(by.model('selection')); - - it('should start in settings', function() { - expect(switchElem.getText()).toMatch(/Settings Div/); - }); - it('should change to home', function() { - select.all(by.css('option')).get(1).click(); - expect(switchElem.getText()).toMatch(/Home Span/); - }); - it('should select default', function() { - select.all(by.css('option')).get(2).click(); - expect(switchElem.getText()).toMatch(/default/); - }); - -
- */ -var ngSwitchDirective = ['$animate', function($animate) { - return { - restrict: 'EA', - require: 'ngSwitch', - - // asks for $scope to fool the BC controller module - controller: ['$scope', function ngSwitchController() { - this.cases = {}; - }], - link: function(scope, element, attr, ngSwitchController) { - var watchExpr = attr.ngSwitch || attr.on, - selectedTranscludes = [], - selectedElements = [], - previousElements = [], - selectedScopes = []; - - scope.$watch(watchExpr, function ngSwitchWatchAction(value) { - var i, ii; - for (i = 0, ii = previousElements.length; i < ii; ++i) { - previousElements[i].remove(); - } - previousElements.length = 0; - - for (i = 0, ii = selectedScopes.length; i < ii; ++i) { - var selected = selectedElements[i]; - selectedScopes[i].$destroy(); - previousElements[i] = selected; - $animate.leave(selected, function() { - previousElements.splice(i, 1); - }); - } - - selectedElements.length = 0; - selectedScopes.length = 0; - - if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) { - scope.$eval(attr.change); - forEach(selectedTranscludes, function(selectedTransclude) { - var selectedScope = scope.$new(); - selectedScopes.push(selectedScope); - selectedTransclude.transclude(selectedScope, function(caseElement) { - var anchor = selectedTransclude.element; - - selectedElements.push(caseElement); - $animate.enter(caseElement, anchor.parent(), anchor); - }); - }); - } - }); - } - }; -}]; - -var ngSwitchWhenDirective = ngDirective({ - transclude: 'element', - priority: 800, - require: '^ngSwitch', - link: function(scope, element, attrs, ctrl, $transclude) { - ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []); - ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element }); - } -}); - -var ngSwitchDefaultDirective = ngDirective({ - transclude: 'element', - priority: 800, - require: '^ngSwitch', - link: function(scope, element, attr, ctrl, $transclude) { - ctrl.cases['?'] = (ctrl.cases['?'] || []); - ctrl.cases['?'].push({ transclude: $transclude, element: element }); - } -}); - -/** - * @ngdoc directive - * @name ngTransclude - * @restrict AC - * - * @description - * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion. - * - * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted. - * - * @element ANY - * - * @example - - - -
-
-
- {{text}} -
-
- - it('should have transcluded', function() { - var titleElement = element(by.model('title')); - titleElement.clear(); - titleElement.sendKeys('TITLE'); - var textElement = element(by.model('text')); - textElement.clear(); - textElement.sendKeys('TEXT'); - expect(element(by.binding('title')).getText()).toEqual('TITLE'); - expect(element(by.binding('text')).getText()).toEqual('TEXT'); - }); - -
- * - */ -var ngTranscludeDirective = ngDirective({ - link: function($scope, $element, $attrs, controller, $transclude) { - if (!$transclude) { - throw minErr('ngTransclude')('orphan', - 'Illegal use of ngTransclude directive in the template! ' + - 'No parent directive that requires a transclusion found. ' + - 'Element: {0}', - startingTag($element)); - } - - $transclude(function(clone) { - $element.empty(); - $element.append(clone); - }); - } -}); - -/** - * @ngdoc directive - * @name script - * @restrict E - * - * @description - * Load the content of a ` - - Load inlined template -
- - - it('should load template defined inside script tag', function() { - element(by.css('#tpl-link')).click(); - expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/); - }); - - - */ -var scriptDirective = ['$templateCache', function($templateCache) { - return { - restrict: 'E', - terminal: true, - compile: function(element, attr) { - if (attr.type == 'text/ng-template') { - var templateUrl = attr.id, - text = element[0].text; - - $templateCache.put(templateUrl, text); - } - } - }; -}]; - -var ngOptionsMinErr = minErr('ngOptions'); -/** - * @ngdoc directive - * @name select - * @restrict E - * - * @description - * HTML `SELECT` element with angular data-binding. - * - * # `ngOptions` - * - * The `ngOptions` attribute can be used to dynamically generate a list of `` - * DOM element. - * * `trackexpr`: Used when working with an array of objects. The result of this expression will be - * used to identify the objects in the array. The `trackexpr` will most likely refer to the - * `value` variable (e.g. `value.propertyName`). - * - * @example - - - -
-
    -
  • - Name: - [X] -
  • -
  • - [add] -
  • -
-
- Color (null not allowed): -
- - Color (null allowed): - - -
- - Color grouped by shade: -
- - - Select bogus.
-
- Currently selected: {{ {selected_color:myColor} }} -
-
-
-
- - it('should check ng-options', function() { - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red'); - element.all(by.model('myColor')).first().click(); - element.all(by.css('select[ng-model="myColor"] option')).first().click(); - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black'); - element(by.css('.nullable select[ng-model="myColor"]')).click(); - element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click(); - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null'); - }); - -
- */ - -var ngOptionsDirective = valueFn({ terminal: true }); -// jshint maxlen: false -var selectDirective = ['$compile', '$parse', function($compile, $parse) { - //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888 - var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/, - nullModelCtrl = {$setViewValue: noop}; -// jshint maxlen: 100 - - return { - restrict: 'E', - require: ['select', '?ngModel'], - controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) { - var self = this, - optionsMap = {}, - ngModelCtrl = nullModelCtrl, - nullOption, - unknownOption; - - - self.databound = $attrs.ngModel; - - - self.init = function(ngModelCtrl_, nullOption_, unknownOption_) { - ngModelCtrl = ngModelCtrl_; - nullOption = nullOption_; - unknownOption = unknownOption_; - }; - - - self.addOption = function(value) { - assertNotHasOwnProperty(value, '"option value"'); - optionsMap[value] = true; - - if (ngModelCtrl.$viewValue == value) { - $element.val(value); - if (unknownOption.parent()) unknownOption.remove(); - } - }; - - - self.removeOption = function(value) { - if (this.hasOption(value)) { - delete optionsMap[value]; - if (ngModelCtrl.$viewValue == value) { - this.renderUnknownOption(value); - } - } - }; - - - self.renderUnknownOption = function(val) { - var unknownVal = '? ' + hashKey(val) + ' ?'; - unknownOption.val(unknownVal); - $element.prepend(unknownOption); - $element.val(unknownVal); - unknownOption.prop('selected', true); // needed for IE - }; - - - self.hasOption = function(value) { - return optionsMap.hasOwnProperty(value); - }; - - $scope.$on('$destroy', function() { - // disable unknown option so that we don't do work when the whole select is being destroyed - self.renderUnknownOption = noop; - }); - }], - - link: function(scope, element, attr, ctrls) { - // if ngModel is not defined, we don't need to do anything - if (!ctrls[1]) return; - - var selectCtrl = ctrls[0], - ngModelCtrl = ctrls[1], - multiple = attr.multiple, - optionsExp = attr.ngOptions, - nullOption = false, // if false, user will not be able to select it (used by ngOptions) - emptyOption, - // we can't just jqLite('