From 7a0f3327a65e60ce93970a408a2134cad25d521a Mon Sep 17 00:00:00 2001 From: Martin Donnelly Date: Wed, 10 Aug 2016 13:51:42 +0100 Subject: [PATCH] =?UTF-8?q?=E2=80=9D2016-08-10=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 6148 -> 6148 bytes mdot/mdot_mqtt/mdot_mqtt/.editorconfig | 32 + mdot/mdot_mqtt/mdot_mqtt/.gitignore | 180 + mdot/mdot_mqtt/mdot_mqtt/.jscsrc | 46 + mdot/mdot_mqtt/mdot_mqtt/.jshintrc | 37 + mdot/mdot_mqtt/mdot_mqtt/app.js | 262 + mdot/mdot_mqtt/mdot_mqtt/bower.json | 24 + mdot/mdot_mqtt/mdot_mqtt/gulpfile.js | 117 + mdot/mdot_mqtt/mdot_mqtt/index.js | 28 + .../mdot_mqtt/lib/mqtt/IoTFconnector.js | 130 + .../mdot_mqtt/lib/mqtt/mqttClient.js | 157 + .../mdot_mqtt/lib/mqtt/mqttConnect.js | 353 + .../mdot_mqtt/lib/mqtt/mqttSocket.js | 7 + mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttws31.js | 1791 +++ .../mdot_mqtt/lib/server/db-connector.js | 21 + .../mdot_mqtt/mdot_mqtt/lib/server/db-save.js | 128 + mdot/mdot_mqtt/mdot_mqtt/maker.js | 20 + mdot/mdot_mqtt/mdot_mqtt/package.json | 75 + mdot/mdot_mqtt/mdot_mqtt/process.json | 20 + mdot/mdot_server/mdot_server/.editorconfig | 32 + mdot/mdot_server/mdot_server/.gitignore | 180 + mdot/mdot_server/mdot_server/.jscsrc | 46 + mdot/mdot_server/mdot_server/.jshintrc | 37 + mdot/mdot_server/mdot_server/app.js | 88 + mdot/mdot_server/mdot_server/app/css/app.css | 276 + .../mdot_server/app/css/material-icons.css | 15 + mdot/mdot_server/mdot_server/app/css/mui.css | 1912 ++++ .../mdot_server/app/css/mui.custom.css | 1912 ++++ .../mdot_server/app/css/mui.min.css | 1 + .../mdot_server/app/css/notification.css | 136 + .../app/fav/android-chrome-144x144.png | Bin 0 -> 1955 bytes .../app/fav/android-chrome-192x192.png | Bin 0 -> 2564 bytes .../app/fav/android-chrome-36x36.png | Bin 0 -> 611 bytes .../app/fav/android-chrome-48x48.png | Bin 0 -> 767 bytes .../app/fav/android-chrome-72x72.png | Bin 0 -> 1043 bytes .../app/fav/android-chrome-96x96.png | Bin 0 -> 1319 bytes .../app/fav/apple-icon-57x57-precomposed.png | Bin 0 -> 7660 bytes .../app/fav/apple-icon-60x60-precomposed.png | Bin 0 -> 7338 bytes .../app/fav/apple-icon-72x72-precomposed.png | Bin 0 -> 8157 bytes .../app/fav/apple-touch-icon-114x114.png | Bin 0 -> 1652 bytes .../app/fav/apple-touch-icon-120x120.png | Bin 0 -> 1688 bytes .../app/fav/apple-touch-icon-144x144.png | Bin 0 -> 1955 bytes .../app/fav/apple-touch-icon-152x152.png | Bin 0 -> 1964 bytes .../app/fav/apple-touch-icon-180x180.png | Bin 0 -> 2353 bytes .../app/fav/apple-touch-icon-57x57.png | Bin 0 -> 875 bytes .../app/fav/apple-touch-icon-60x60.png | Bin 0 -> 924 bytes .../app/fav/apple-touch-icon-72x72.png | Bin 0 -> 1043 bytes .../app/fav/apple-touch-icon-76x76.png | Bin 0 -> 1205 bytes .../app/fav/apple-touch-icon-precomposed.png | Bin 0 -> 2948 bytes .../mdot_server/app/fav/apple-touch-icon.png | Bin 0 -> 2353 bytes .../mdot_server/app/fav/browserconfig.xml | 12 + .../app/fav/censis-opengraph-image.png | Bin 0 -> 16511 bytes .../mdot_server/app/fav/favicon-16x16.png | Bin 0 -> 401 bytes .../mdot_server/app/fav/favicon-32x32.png | Bin 0 -> 564 bytes .../mdot_server/app/fav/favicon-96x96.png | Bin 0 -> 1319 bytes .../mdot_server/app/fav/favicon.ico | Bin 0 -> 7406 bytes .../mdot_server/app/fav/manifest.json | 43 + .../mdot_server/app/fav/mstile-144x144.png | Bin 0 -> 1955 bytes .../mdot_server/app/fav/mstile-150x150.png | Bin 0 -> 1478 bytes .../mdot_server/app/fav/mstile-310x150.png | Bin 0 -> 1721 bytes .../mdot_server/app/fav/mstile-310x310.png | Bin 0 -> 2842 bytes .../mdot_server/app/fav/mstile-70x70.png | Bin 0 -> 1250 bytes .../mdot_server/app/fav/safari-pinned-tab.svg | 46 + mdot/mdot_server/mdot_server/app/gfx/100.png | Bin 0 -> 3811 bytes mdot/mdot_server/mdot_server/app/gfx/105.png | Bin 0 -> 3993 bytes mdot/mdot_server/mdot_server/app/gfx/128.png | Bin 0 -> 4298 bytes .../mdot_server/app/gfx/censis_logo_white.png | Bin 0 -> 5975 bytes .../app/gfx/icons/Cellular Network.png | Bin 0 -> 2203 bytes .../app/gfx/icons/Chance of Storm.png | Bin 0 -> 2112 bytes .../mdot_server/app/gfx/icons/Clock.png | Bin 0 -> 1847 bytes .../app/gfx/icons/Cloud Lighting.png | Bin 0 -> 2167 bytes .../mdot_server/app/gfx/icons/Cloud.png | Bin 0 -> 1584 bytes .../app/gfx/icons/Coffee Maker.png | Bin 0 -> 1311 bytes .../mdot_server/app/gfx/icons/Downpour.png | Bin 0 -> 1984 bytes .../app/gfx/icons/Electric Teapot.png | Bin 0 -> 1015 bytes .../mdot_server/app/gfx/icons/Fog Day.png | Bin 0 -> 1452 bytes .../mdot_server/app/gfx/icons/Fog Night.png | Bin 0 -> 1553 bytes .../mdot_server/app/gfx/icons/Full Moon.png | Bin 0 -> 1757 bytes .../mdot_server/app/gfx/icons/Hail.png | Bin 0 -> 2022 bytes .../mdot_server/app/gfx/icons/Heavy Rain.png | Bin 0 -> 1844 bytes .../mdot_server/app/gfx/icons/Icy.png | Bin 0 -> 1412 bytes .../mdot_server/app/gfx/icons/Idea.png | Bin 0 -> 1867 bytes .../app/gfx/icons/Intense Rain.png | Bin 0 -> 1844 bytes .../app/gfx/icons/Light Automation.png | Bin 0 -> 1987 bytes .../mdot_server/app/gfx/icons/Light Off.png | Bin 0 -> 1785 bytes .../app/gfx/icons/Light Rain 2.png | Bin 0 -> 1883 bytes .../mdot_server/app/gfx/icons/Light Rain.png | Bin 0 -> 1816 bytes .../mdot_server/app/gfx/icons/Light Snow.png | Bin 0 -> 2032 bytes .../app/gfx/icons/Lightning Bolt.png | Bin 0 -> 1247 bytes .../app/gfx/icons/Moderate Rain.png | Bin 0 -> 1861 bytes .../mdot_server/app/gfx/icons/No Rain.png | Bin 0 -> 2169 bytes .../app/gfx/icons/Partly Cloudy Day.png | Bin 0 -> 1730 bytes .../app/gfx/icons/Partly Cloudy Night.png | Bin 0 -> 1834 bytes .../app/gfx/icons/Partly Cloudy Rain.png | Bin 0 -> 2115 bytes .../mdot_server/app/gfx/icons/Rain.png | Bin 0 -> 2130 bytes .../mdot_server/app/gfx/icons/Sleet.png | Bin 0 -> 2139 bytes .../mdot_server/app/gfx/icons/Snow Storm.png | Bin 0 -> 1717 bytes .../mdot_server/app/gfx/icons/Snow.png | Bin 0 -> 2288 bytes .../mdot_server/app/gfx/icons/Storm.png | Bin 0 -> 1929 bytes .../mdot_server/app/gfx/icons/Sun.png | Bin 0 -> 1623 bytes .../mdot_server/app/gfx/icons/TV On.png | Bin 0 -> 1166 bytes .../app/gfx/icons/Temperature Outside.png | Bin 0 -> 1318 bytes .../app/gfx/icons/Thermometer Automation.png | Bin 0 -> 1728 bytes .../app/gfx/icons/Torrential Rain.png | Bin 0 -> 1945 bytes .../mdot_server/app/gfx/icons/Wet.png | Bin 0 -> 1806 bytes .../mdot_server/app/gfx/icons/Winter.png | Bin 0 -> 2250 bytes .../app/gfx/icons/air-conditioner.png | Bin 0 -> 1591 bytes .../mdot_server/app/gfx/icons/av-receiver.png | Bin 0 -> 1408 bytes .../mdot_server/app/gfx/icons/bright-moon.png | Bin 0 -> 1743 bytes .../mdot_server/app/gfx/icons/calendar.png | Bin 0 -> 894 bytes .../mdot_server/app/gfx/icons/fan.png | Bin 0 -> 1977 bytes .../mdot_server/app/gfx/icons/globe-bulb.png | Bin 0 -> 1607 bytes .../app/gfx/icons/video-projector.png | Bin 0 -> 1155 bytes .../light-bulb-vector-png-light-bulb-10.svg | 16 + .../mdot_server/app/gfx/projector.gif | Bin 0 -> 2023 bytes .../mdot_server/app/gfx/projector.png | Bin 0 -> 31532 bytes mdot/mdot_server/mdot_server/app/index.html | 318 + mdot/mdot_server/mdot_server/app/js/mdot.js | 412 + .../mdot_server/app/lib/backbone.js | 1920 ++++ .../mdot_server/mdot_server/app/lib/base64.js | 61 + .../mdot_server/mdot_server/app/lib/chroma.js | 2465 +++++ .../mdot_server/mdot_server/app/lib/jquery.js | 9842 +++++++++++++++++ .../mdot_server/app/lib/knockout.debug.js | 5871 ++++++++++ .../mdot_server/app/lib/microevent.js | 55 + mdot/mdot_server/mdot_server/app/lib/mui.js | 1809 +++ .../mdot_server/app/lib/notification.js | 1958 ++++ .../mdot_server/app/lib/skycons.js | 730 ++ .../mdot_server/app/lib/sugar-date.js | 3335 ++++++ .../mdot_server/app/lib/sugar-full.min.js | 200 + .../mdot_server/app/lib/underscore.js | 1548 +++ mdot/mdot_server/mdot_server/app/test.html | 179 + mdot/mdot_server/mdot_server/bower.json | 27 + mdot/mdot_server/mdot_server/lib/mdot/api.js | 48 + mdot/mdot_server/mdot_server/lib/mdot/mdot.js | 88 + mdot/mdot_server/mdot_server/package.json | 83 + mdot/mdot_server/mdot_server/process.json | 20 + .../src/bower_modules/backbone/.bower.json | 31 + .../src/bower_modules/backbone/LICENSE | 22 + .../bower_modules/backbone/backbone-min.js | 2 + .../bower_modules/backbone/backbone-min.map | 1 + .../src/bower_modules/backbone/backbone.js | 1920 ++++ .../src/bower_modules/backbone/bower.json | 8 + .../src/bower_modules/base64/.bower.json | 28 + .../src/bower_modules/base64/LICENSE | 219 + .../src/bower_modules/base64/README.md | 34 + .../src/bower_modules/base64/base64.js | 61 + .../src/bower_modules/base64/base64.min.js | 1 + .../src/bower_modules/base64/bower.json | 18 + .../src/bower_modules/base64/package.json | 25 + .../src/bower_modules/chroma-js/.bower.json | 43 + .../src/bower_modules/chroma-js/CHANGELOG | 21 + .../src/bower_modules/chroma-js/Gruntfile.js | 74 + .../src/bower_modules/chroma-js/LICENSE | 28 + .../bower_modules/chroma-js/LICENSE-colors | 22 + .../src/bower_modules/chroma-js/bower.json | 33 + .../src/bower_modules/chroma-js/chroma.js | 2465 +++++ .../src/bower_modules/chroma-js/chroma.min.js | 33 + .../src/bower_modules/chroma-js/package.json | 52 + .../src/bower_modules/chroma-js/readme.md | 89 + .../src/bower_modules/jquery/.bower.json | 25 + .../src/bower_modules/jquery/AUTHORS.txt | 278 + .../src/bower_modules/jquery/LICENSE.txt | 36 + .../src/bower_modules/jquery/README.md | 65 + .../src/bower_modules/jquery/bower.json | 14 + .../jquery/external/sizzle/LICENSE.txt | 36 + .../src/bower_modules/jquery/src/.jshintrc | 29 + .../src/bower_modules/jquery/src/ajax.js | 845 ++ .../bower_modules/jquery/src/ajax/jsonp.js | 100 + .../src/bower_modules/jquery/src/ajax/load.js | 83 + .../jquery/src/ajax/parseJSON.js | 13 + .../bower_modules/jquery/src/ajax/parseXML.js | 27 + .../bower_modules/jquery/src/ajax/script.js | 68 + .../jquery/src/ajax/var/location.js | 3 + .../jquery/src/ajax/var/nonce.js | 5 + .../jquery/src/ajax/var/rquery.js | 3 + .../src/bower_modules/jquery/src/ajax/xhr.js | 167 + .../bower_modules/jquery/src/attributes.js | 11 + .../jquery/src/attributes/attr.js | 142 + .../jquery/src/attributes/classes.js | 177 + .../jquery/src/attributes/prop.js | 125 + .../jquery/src/attributes/support.js | 36 + .../jquery/src/attributes/val.js | 177 + .../src/bower_modules/jquery/src/callbacks.js | 232 + .../src/bower_modules/jquery/src/core.js | 494 + .../bower_modules/jquery/src/core/access.js | 65 + .../src/bower_modules/jquery/src/core/init.js | 134 + .../jquery/src/core/parseHTML.js | 41 + .../bower_modules/jquery/src/core/ready.js | 103 + .../jquery/src/core/var/rsingleTag.js | 5 + .../src/bower_modules/jquery/src/css.js | 502 + .../jquery/src/css/addGetHookIf.js | 24 + .../bower_modules/jquery/src/css/adjustCSS.js | 65 + .../bower_modules/jquery/src/css/curCSS.js | 60 + .../jquery/src/css/defaultDisplay.js | 72 + .../jquery/src/css/hiddenVisibleSelectors.js | 18 + .../bower_modules/jquery/src/css/showHide.js | 48 + .../bower_modules/jquery/src/css/support.js | 121 + .../jquery/src/css/var/cssExpand.js | 3 + .../jquery/src/css/var/getStyles.js | 15 + .../jquery/src/css/var/isHidden.js | 16 + .../jquery/src/css/var/rmargin.js | 3 + .../jquery/src/css/var/rnumnonpx.js | 5 + .../bower_modules/jquery/src/css/var/swap.js | 24 + .../src/bower_modules/jquery/src/data.js | 187 + .../src/bower_modules/jquery/src/data/Data.js | 200 + .../jquery/src/data/var/acceptData.js | 18 + .../jquery/src/data/var/dataPriv.js | 5 + .../jquery/src/data/var/dataUser.js | 5 + .../src/bower_modules/jquery/src/deferred.js | 158 + .../bower_modules/jquery/src/deprecated.js | 32 + .../bower_modules/jquery/src/dimensions.js | 54 + .../src/bower_modules/jquery/src/effects.js | 629 ++ .../bower_modules/jquery/src/effects/Tween.js | 121 + .../jquery/src/effects/animatedSelector.js | 13 + .../src/bower_modules/jquery/src/event.js | 711 ++ .../bower_modules/jquery/src/event/ajax.js | 20 + .../bower_modules/jquery/src/event/alias.js | 27 + .../bower_modules/jquery/src/event/focusin.js | 53 + .../bower_modules/jquery/src/event/support.js | 9 + .../bower_modules/jquery/src/event/trigger.js | 183 + .../bower_modules/jquery/src/exports/amd.js | 24 + .../jquery/src/exports/global.js | 26 + .../src/bower_modules/jquery/src/intro.js | 44 + .../src/bower_modules/jquery/src/jquery.js | 37 + .../bower_modules/jquery/src/manipulation.js | 481 + .../jquery/src/manipulation/_evalUrl.js | 20 + .../jquery/src/manipulation/buildFragment.js | 102 + .../jquery/src/manipulation/getAll.js | 21 + .../jquery/src/manipulation/setGlobalEval.js | 20 + .../jquery/src/manipulation/support.js | 33 + .../src/manipulation/var/rcheckableType.js | 3 + .../src/manipulation/var/rscriptType.js | 3 + .../jquery/src/manipulation/var/rtagName.js | 3 + .../jquery/src/manipulation/wrapMap.js | 27 + .../src/bower_modules/jquery/src/offset.js | 218 + .../src/bower_modules/jquery/src/outro.js | 2 + .../src/bower_modules/jquery/src/queue.js | 143 + .../bower_modules/jquery/src/queue/delay.js | 22 + .../jquery/src/selector-native.js | 211 + .../jquery/src/selector-sizzle.js | 14 + .../src/bower_modules/jquery/src/selector.js | 1 + .../src/bower_modules/jquery/src/serialize.js | 125 + .../bower_modules/jquery/src/traversing.js | 175 + .../jquery/src/traversing/findFilter.js | 100 + .../jquery/src/traversing/var/dir.js | 20 + .../src/traversing/var/rneedsContext.js | 6 + .../jquery/src/traversing/var/siblings.js | 15 + .../src/bower_modules/jquery/src/var/arr.js | 3 + .../jquery/src/var/class2type.js | 5 + .../bower_modules/jquery/src/var/concat.js | 5 + .../bower_modules/jquery/src/var/document.js | 3 + .../jquery/src/var/documentElement.js | 5 + .../bower_modules/jquery/src/var/hasOwn.js | 5 + .../bower_modules/jquery/src/var/indexOf.js | 5 + .../src/bower_modules/jquery/src/var/pnum.js | 3 + .../src/bower_modules/jquery/src/var/push.js | 5 + .../bower_modules/jquery/src/var/rcssNum.js | 7 + .../bower_modules/jquery/src/var/rnotwhite.js | 3 + .../src/bower_modules/jquery/src/var/slice.js | 5 + .../bower_modules/jquery/src/var/support.js | 5 + .../bower_modules/jquery/src/var/toString.js | 5 + .../src/bower_modules/jquery/src/wrap.js | 79 + .../src/bower_modules/mui/.bower.json | 50 + .../src/bower_modules/mui/AUTHORS.txt | 8 + .../src/bower_modules/mui/CHANGELOG.md | 425 + .../src/bower_modules/mui/LICENSE.txt | 33 + .../src/bower_modules/mui/README.md | 165 + .../src/bower_modules/mui/RELEASE.md | 45 + .../src/bower_modules/mui/bower.json | 42 + .../mui/packages/cdn/angular/mui-angular.js | 1924 ++++ .../packages/cdn/angular/mui-angular.min.js | 1 + .../mui/packages/cdn/css/mui.css | 2573 +++++ .../mui/packages/cdn/css/mui.min.css | 1 + .../packages/cdn/email/mui-email-inline.css | 686 ++ .../packages/cdn/email/mui-email-styletag.css | 36 + .../cdn/extra/mui-angular-combined.js | 2 + .../mui/packages/cdn/extra/mui-colors.css | 1 + .../mui/packages/cdn/extra/mui-combined.js | 2 + .../packages/cdn/extra/mui-react-combined.js | 2 + .../bower_modules/mui/packages/cdn/js/mui.js | 1868 ++++ .../mui/packages/cdn/js/mui.min.js | 1 + .../mui/packages/cdn/react/mui-react.js | 3375 ++++++ .../mui/packages/cdn/react/mui-react.min.js | 2 + .../cdn/webcomponents/mui-webcomponents.js | 1031 ++ .../webcomponents/mui-webcomponents.min.js | 2 + .../mui/packages/meteor/LICENSE.txt | 31 + .../mui/packages/meteor/README.md | 45 + .../mui/packages/meteor/lib/css/mui.css | 2573 +++++ .../mui/packages/meteor/lib/css/mui.min.css | 1 + .../mui/packages/meteor/lib/js/mui.js | 1868 ++++ .../mui/packages/meteor/lib/js/mui.min.js | 1 + .../mui/packages/meteor/package.js | 22 + .../mui/packages/npm/LICENSE.txt | 31 + .../bower_modules/mui/packages/npm/README.md | 497 + .../bower_modules/mui/packages/npm/angular.js | 31 + .../bower_modules/mui/packages/npm/index.js | 9 + .../mui/packages/npm/lib/angular/appbar.js | 34 + .../packages/npm/lib/angular/babel-helpers.js | 34 + .../mui/packages/npm/lib/angular/button.js | 157 + .../mui/packages/npm/lib/angular/caret.js | 27 + .../mui/packages/npm/lib/angular/checkbox.js | 35 + .../mui/packages/npm/lib/angular/col.js | 52 + .../mui/packages/npm/lib/angular/container.js | 40 + .../mui/packages/npm/lib/angular/divider.js | 29 + .../packages/npm/lib/angular/dropdown-item.js | 31 + .../mui/packages/npm/lib/angular/dropdown.js | 93 + .../mui/packages/npm/lib/angular/form.js | 28 + .../mui/packages/npm/lib/angular/input.js | 146 + .../mui/packages/npm/lib/angular/panel.js | 34 + .../mui/packages/npm/lib/angular/radio.js | 35 + .../mui/packages/npm/lib/angular/row.js | 34 + .../mui/packages/npm/lib/angular/select.js | 257 + .../mui/packages/npm/lib/angular/tabs.js | 128 + .../mui/packages/npm/lib/css/mui.css | 2573 +++++ .../mui/packages/npm/lib/css/mui.min.css | 1 + .../mui/packages/npm/lib/js/config.js | 10 + .../mui/packages/npm/lib/js/lib/forms.js | 59 + .../mui/packages/npm/lib/js/lib/jqLite.js | 398 + .../mui/packages/npm/lib/js/lib/util.js | 261 + .../mui/packages/npm/lib/js/overlay.js | 192 + .../mui/packages/npm/lib/react/_helpers.js | 12 + .../mui/packages/npm/lib/react/appbar.js | 57 + .../packages/npm/lib/react/babel-helpers.js | 108 + .../mui/packages/npm/lib/react/button.js | 315 + .../mui/packages/npm/lib/react/caret.js | 53 + .../mui/packages/npm/lib/react/checkbox.js | 99 + .../mui/packages/npm/lib/react/col.js | 104 + .../mui/packages/npm/lib/react/container.js | 68 + .../mui/packages/npm/lib/react/divider.js | 54 + .../packages/npm/lib/react/dropdown-item.js | 79 + .../mui/packages/npm/lib/react/dropdown.js | 249 + .../mui/packages/npm/lib/react/form.js | 67 + .../mui/packages/npm/lib/react/input.js | 50 + .../mui/packages/npm/lib/react/option.js | 75 + .../mui/packages/npm/lib/react/panel.js | 58 + .../mui/packages/npm/lib/react/radio.js | 93 + .../mui/packages/npm/lib/react/row.js | 65 + .../mui/packages/npm/lib/react/select.js | 465 + .../mui/packages/npm/lib/react/tab.js | 57 + .../mui/packages/npm/lib/react/tabs.js | 148 + .../mui/packages/npm/lib/react/text-field.js | 291 + .../mui/packages/npm/lib/react/textarea.js | 47 + .../mui/packages/npm/lib/sass/mui-colors.scss | 34 + .../mui/packages/npm/lib/sass/mui.scss | 36 + .../packages/npm/lib/sass/mui/_appbar.scss | 44 + .../packages/npm/lib/sass/mui/_buttons.scss | 233 + .../npm/lib/sass/mui/_checkbox-and-radio.scss | 60 + .../packages/npm/lib/sass/mui/_colors.scss | 340 + .../npm/lib/sass/mui/_containers.scss | 24 + .../packages/npm/lib/sass/mui/_divider.scss | 25 + .../packages/npm/lib/sass/mui/_dropdown.scss | 90 + .../mui/packages/npm/lib/sass/mui/_form.scss | 40 + .../mui/packages/npm/lib/sass/mui/_grid.scss | 37 + .../packages/npm/lib/sass/mui/_helpers.scss | 342 + .../packages/npm/lib/sass/mui/_mixins.scss | 5 + .../packages/npm/lib/sass/mui/_overlay.scss | 14 + .../mui/packages/npm/lib/sass/mui/_panel.scss | 22 + .../packages/npm/lib/sass/mui/_reboot.scss | 182 + .../packages/npm/lib/sass/mui/_ripple.scss | 61 + .../packages/npm/lib/sass/mui/_select.scss | 120 + .../mui/packages/npm/lib/sass/mui/_table.scss | 44 + .../mui/packages/npm/lib/sass/mui/_tabs.scss | 75 + .../packages/npm/lib/sass/mui/_textfield.scss | 218 + .../npm/lib/sass/mui/_typography.scss | 51 + .../packages/npm/lib/sass/mui/_variables.scss | 293 + .../npm/lib/sass/mui/mixins/_buttons.scss | 52 + .../npm/lib/sass/mui/mixins/_forms.scss | 18 + .../lib/sass/mui/mixins/_grid-framework.scss | 51 + .../npm/lib/sass/mui/mixins/_typography.scss | 78 + .../npm/lib/sass/mui/mixins/_util.scss | 45 + .../npm/lib/sass/normalize-3.0.3.scss | 424 + .../bower_modules/mui/packages/npm/react.js | 27 + .../bower_modules/mui/src/angular/appbar.js | 30 + .../bower_modules/mui/src/angular/button.js | 151 + .../bower_modules/mui/src/angular/caret.js | 23 + .../bower_modules/mui/src/angular/checkbox.js | 39 + .../src/bower_modules/mui/src/angular/col.js | 48 + .../mui/src/angular/container.js | 36 + .../bower_modules/mui/src/angular/divider.js | 25 + .../mui/src/angular/dropdown-item.js | 27 + .../bower_modules/mui/src/angular/dropdown.js | 99 + .../src/bower_modules/mui/src/angular/form.js | 24 + .../bower_modules/mui/src/angular/input.js | 159 + .../bower_modules/mui/src/angular/panel.js | 30 + .../bower_modules/mui/src/angular/radio.js | 39 + .../src/bower_modules/mui/src/angular/row.js | 30 + .../bower_modules/mui/src/angular/select.js | 286 + .../src/bower_modules/mui/src/angular/tabs.js | 133 + .../mui/src/email/mui-email-inline.scss | 28 + .../mui/src/email/mui-email-styletag.scss | 11 + .../mui/src/email/mui-email/_body.scss | 20 + .../mui/src/email/mui-email/_buttons.scss | 250 + .../mui/src/email/mui-email/_containers.scss | 18 + .../mui/src/email/mui-email/_divider.scss | 25 + .../mui/src/email/mui-email/_grid.scss | 32 + .../mui/src/email/mui-email/_helpers.scss | 46 + .../mui/src/email/mui-email/_normalize.scss | 60 + .../mui/src/email/mui-email/_panel.scss | 13 + .../mui/src/email/mui-email/_reboot.scss | 66 + .../mui/src/email/mui-email/_styletag.scss | 53 + .../mui/src/email/mui-email/_typography.scss | 51 + .../mui/src/email/mui-email/_variables.scss | 135 + .../src/bower_modules/mui/src/js/config.js | 10 + .../src/bower_modules/mui/src/js/dropdown.js | 111 + .../src/bower_modules/mui/src/js/lib/forms.js | 59 + .../bower_modules/mui/src/js/lib/jqLite.js | 398 + .../src/bower_modules/mui/src/js/lib/util.js | 261 + .../src/bower_modules/mui/src/js/overlay.js | 192 + .../src/bower_modules/mui/src/js/ripple.js | 155 + .../src/bower_modules/mui/src/js/select.js | 363 + .../src/bower_modules/mui/src/js/tabs.js | 159 + .../src/bower_modules/mui/src/js/textfield.js | 99 + .../bower_modules/mui/src/react/_helpers.js | 15 + .../bower_modules/mui/src/react/appbar.jsx | 36 + .../bower_modules/mui/src/react/button.jsx | 260 + .../src/bower_modules/mui/src/react/caret.jsx | 35 + .../bower_modules/mui/src/react/checkbox.jsx | 66 + .../src/bower_modules/mui/src/react/col.jsx | 78 + .../bower_modules/mui/src/react/container.jsx | 46 + .../bower_modules/mui/src/react/divider.jsx | 35 + .../mui/src/react/dropdown-item.jsx | 50 + .../bower_modules/mui/src/react/dropdown.jsx | 203 + .../src/bower_modules/mui/src/react/form.jsx | 45 + .../src/bower_modules/mui/src/react/input.jsx | 35 + .../bower_modules/mui/src/react/option.jsx | 41 + .../src/bower_modules/mui/src/react/panel.jsx | 36 + .../src/bower_modules/mui/src/react/radio.jsx | 62 + .../src/bower_modules/mui/src/react/row.jsx | 41 + .../bower_modules/mui/src/react/select.jsx | 396 + .../src/bower_modules/mui/src/react/tab.jsx | 40 + .../src/bower_modules/mui/src/react/tabs.jsx | 117 + .../mui/src/react/text-field.jsx | 231 + .../bower_modules/mui/src/react/textarea.jsx | 31 + .../mui/src/sass/mui-colors.scss | 34 + .../src/bower_modules/mui/src/sass/mui.scss | 36 + .../mui/src/sass/mui/_appbar.scss | 44 + .../mui/src/sass/mui/_buttons.scss | 233 + .../mui/src/sass/mui/_checkbox-and-radio.scss | 60 + .../mui/src/sass/mui/_colors.scss | 340 + .../mui/src/sass/mui/_containers.scss | 24 + .../mui/src/sass/mui/_divider.scss | 25 + .../mui/src/sass/mui/_dropdown.scss | 90 + .../bower_modules/mui/src/sass/mui/_form.scss | 40 + .../bower_modules/mui/src/sass/mui/_grid.scss | 37 + .../mui/src/sass/mui/_helpers.scss | 342 + .../mui/src/sass/mui/_mixins.scss | 5 + .../mui/src/sass/mui/_overlay.scss | 14 + .../mui/src/sass/mui/_panel.scss | 22 + .../mui/src/sass/mui/_reboot.scss | 182 + .../mui/src/sass/mui/_ripple.scss | 61 + .../mui/src/sass/mui/_select.scss | 120 + .../mui/src/sass/mui/_table.scss | 44 + .../bower_modules/mui/src/sass/mui/_tabs.scss | 75 + .../mui/src/sass/mui/_textfield.scss | 218 + .../mui/src/sass/mui/_typography.scss | 51 + .../mui/src/sass/mui/_variables.scss | 293 + .../mui/src/sass/mui/mixins/_buttons.scss | 52 + .../mui/src/sass/mui/mixins/_forms.scss | 18 + .../src/sass/mui/mixins/_grid-framework.scss | 51 + .../mui/src/sass/mui/mixins/_typography.scss | 78 + .../mui/src/sass/mui/mixins/_util.scss | 45 + .../mui/src/sass/normalize-3.0.3.scss | 424 + .../mui/src/webcomponents/buttons.js | 89 + .../mui/src/webcomponents/forms.js | 133 + .../bower_modules/notification-js/.bower.json | 53 + .../notification-js/CHANGELOG.md | 78 + .../notification-js/Gruntfile.js | 155 + .../src/bower_modules/notification-js/LICENSE | 22 + .../bower_modules/notification-js/README.md | 862 ++ .../bower_modules/notification-js/bower.json | 42 + .../notification-js/package.json | 44 + .../notification-js/src/notification.css | 136 + .../notification-js/src/notification.js | 1958 ++++ .../bower_modules/sugarjs-date/.bower.json | 36 + .../src/bower_modules/sugarjs-date/README.md | 42 + .../src/bower_modules/sugarjs-date/bower.json | 27 + .../src/bower_modules/sugarjs-date/build | 11 + .../bower_modules/sugarjs-date/package.json | 14 + .../bower_modules/sugarjs-date/sugar-date.js | 3335 ++++++ .../sugarjs-date/sugar-date.min.js | 68 + .../src/bower_modules/underscore/.bower.json | 35 + .../src/bower_modules/underscore/LICENSE | 23 + .../src/bower_modules/underscore/README.md | 22 + .../src/bower_modules/underscore/bower.json | 7 + .../underscore/underscore-min.js | 6 + .../underscore/underscore-min.map | 1 + .../bower_modules/underscore/underscore.js | 1548 +++ 487 files changed, 98627 insertions(+) create mode 100644 mdot/mdot_mqtt/mdot_mqtt/.editorconfig create mode 100644 mdot/mdot_mqtt/mdot_mqtt/.gitignore create mode 100644 mdot/mdot_mqtt/mdot_mqtt/.jscsrc create mode 100644 mdot/mdot_mqtt/mdot_mqtt/.jshintrc create mode 100644 mdot/mdot_mqtt/mdot_mqtt/app.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/bower.json create mode 100644 mdot/mdot_mqtt/mdot_mqtt/gulpfile.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/index.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/IoTFconnector.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttClient.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttConnect.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttSocket.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttws31.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/server/db-connector.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/lib/server/db-save.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/maker.js create mode 100644 mdot/mdot_mqtt/mdot_mqtt/package.json create mode 100644 mdot/mdot_mqtt/mdot_mqtt/process.json create mode 100644 mdot/mdot_server/mdot_server/.editorconfig create mode 100644 mdot/mdot_server/mdot_server/.gitignore create mode 100644 mdot/mdot_server/mdot_server/.jscsrc create mode 100644 mdot/mdot_server/mdot_server/.jshintrc create mode 100644 mdot/mdot_server/mdot_server/app.js create mode 100644 mdot/mdot_server/mdot_server/app/css/app.css create mode 100644 mdot/mdot_server/mdot_server/app/css/material-icons.css create mode 100644 mdot/mdot_server/mdot_server/app/css/mui.css create mode 100644 mdot/mdot_server/mdot_server/app/css/mui.custom.css create mode 100644 mdot/mdot_server/mdot_server/app/css/mui.min.css create mode 100644 mdot/mdot_server/mdot_server/app/css/notification.css create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-144x144.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-192x192.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-36x36.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-48x48.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-72x72.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/android-chrome-96x96.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-icon-57x57-precomposed.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-icon-60x60-precomposed.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-icon-72x72-precomposed.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-114x114.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-120x120.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-144x144.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-152x152.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-180x180.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-57x57.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-60x60.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-72x72.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-76x76.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-precomposed.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/apple-touch-icon.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/browserconfig.xml create mode 100644 mdot/mdot_server/mdot_server/app/fav/censis-opengraph-image.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/favicon-16x16.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/favicon-32x32.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/favicon-96x96.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/favicon.ico create mode 100644 mdot/mdot_server/mdot_server/app/fav/manifest.json create mode 100644 mdot/mdot_server/mdot_server/app/fav/mstile-144x144.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/mstile-150x150.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/mstile-310x150.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/mstile-310x310.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/mstile-70x70.png create mode 100644 mdot/mdot_server/mdot_server/app/fav/safari-pinned-tab.svg create mode 100644 mdot/mdot_server/mdot_server/app/gfx/100.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/105.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/128.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/censis_logo_white.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Cellular Network.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Chance of Storm.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Clock.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Cloud Lighting.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Cloud.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Coffee Maker.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Downpour.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Electric Teapot.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Fog Day.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Fog Night.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Full Moon.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Hail.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Heavy Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Icy.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Idea.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Intense Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Light Automation.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Light Off.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain 2.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Light Snow.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Lightning Bolt.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Moderate Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/No Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Day.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Night.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Sleet.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Snow Storm.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Snow.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Storm.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Sun.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/TV On.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Temperature Outside.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Thermometer Automation.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Torrential Rain.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Wet.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/Winter.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/air-conditioner.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/av-receiver.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/bright-moon.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/calendar.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/fan.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/globe-bulb.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/icons/video-projector.png create mode 100644 mdot/mdot_server/mdot_server/app/gfx/light-bulb-vector-png-light-bulb-10.svg create mode 100644 mdot/mdot_server/mdot_server/app/gfx/projector.gif create mode 100644 mdot/mdot_server/mdot_server/app/gfx/projector.png create mode 100644 mdot/mdot_server/mdot_server/app/index.html create mode 100644 mdot/mdot_server/mdot_server/app/js/mdot.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/backbone.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/base64.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/chroma.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/jquery.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/knockout.debug.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/microevent.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/mui.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/notification.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/skycons.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/sugar-date.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/sugar-full.min.js create mode 100644 mdot/mdot_server/mdot_server/app/lib/underscore.js create mode 100644 mdot/mdot_server/mdot_server/app/test.html create mode 100644 mdot/mdot_server/mdot_server/bower.json create mode 100644 mdot/mdot_server/mdot_server/lib/mdot/api.js create mode 100644 mdot/mdot_server/mdot_server/lib/mdot/mdot.js create mode 100644 mdot/mdot_server/mdot_server/package.json create mode 100644 mdot/mdot_server/mdot_server/process.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/LICENSE create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/backbone-min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/backbone-min.map create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/backbone.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/backbone/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/LICENSE create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/base64.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/base64.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/base64/package.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/CHANGELOG create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/Gruntfile.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/LICENSE create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/LICENSE-colors create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/chroma.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/chroma.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/package.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/chroma-js/readme.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/AUTHORS.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/LICENSE.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/external/sizzle/LICENSE.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/.jshintrc create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/jsonp.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/load.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/parseJSON.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/parseXML.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/script.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/var/location.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/var/nonce.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/var/rquery.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/ajax/xhr.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes/attr.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes/classes.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes/prop.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes/support.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/attributes/val.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/callbacks.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core/access.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core/init.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core/parseHTML.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core/ready.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/core/var/rsingleTag.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/addGetHookIf.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/adjustCSS.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/curCSS.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/defaultDisplay.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/hiddenVisibleSelectors.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/showHide.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/support.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/cssExpand.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/getStyles.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/isHidden.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/rmargin.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/rnumnonpx.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/css/var/swap.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/data.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/data/Data.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/data/var/acceptData.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/data/var/dataPriv.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/data/var/dataUser.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/deferred.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/deprecated.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/dimensions.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/effects.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/effects/Tween.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/effects/animatedSelector.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event/ajax.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event/alias.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event/focusin.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event/support.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/event/trigger.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/exports/amd.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/exports/global.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/intro.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/jquery.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/_evalUrl.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/buildFragment.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/getAll.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/setGlobalEval.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/support.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/var/rcheckableType.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/var/rscriptType.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/var/rtagName.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/manipulation/wrapMap.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/offset.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/outro.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/queue.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/queue/delay.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/selector-native.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/selector-sizzle.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/selector.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/serialize.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/traversing.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/traversing/findFilter.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/traversing/var/dir.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/traversing/var/rneedsContext.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/traversing/var/siblings.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/arr.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/class2type.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/concat.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/document.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/documentElement.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/hasOwn.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/indexOf.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/pnum.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/push.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/rcssNum.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/rnotwhite.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/slice.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/support.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/var/toString.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/jquery/src/wrap.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/AUTHORS.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/CHANGELOG.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/LICENSE.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/RELEASE.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/angular/mui-angular.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/angular/mui-angular.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/css/mui.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/css/mui.min.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/email/mui-email-inline.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/email/mui-email-styletag.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/extra/mui-angular-combined.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/extra/mui-colors.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/extra/mui-combined.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/extra/mui-react-combined.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/js/mui.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/js/mui.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/react/mui-react.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/react/mui-react.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/webcomponents/mui-webcomponents.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/cdn/webcomponents/mui-webcomponents.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/LICENSE.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/lib/css/mui.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/lib/css/mui.min.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/lib/js/mui.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/lib/js/mui.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/meteor/package.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/LICENSE.txt create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/angular.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/index.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/appbar.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/babel-helpers.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/button.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/caret.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/checkbox.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/col.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/container.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/divider.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/dropdown-item.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/dropdown.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/form.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/input.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/panel.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/radio.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/row.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/select.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/angular/tabs.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/css/mui.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/css/mui.min.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/js/config.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/js/lib/forms.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/js/lib/jqLite.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/js/lib/util.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/js/overlay.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/_helpers.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/appbar.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/babel-helpers.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/button.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/caret.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/checkbox.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/col.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/container.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/divider.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/dropdown-item.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/dropdown.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/form.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/input.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/option.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/panel.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/radio.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/row.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/select.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/tab.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/tabs.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/text-field.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/react/textarea.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui-colors.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_appbar.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_buttons.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_checkbox-and-radio.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_colors.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_containers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_divider.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_dropdown.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_form.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_grid.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_helpers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_mixins.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_overlay.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_panel.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_reboot.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_ripple.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_select.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_table.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_tabs.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_textfield.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_typography.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/_variables.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/mixins/_buttons.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/mixins/_forms.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/mixins/_grid-framework.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/mixins/_typography.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/mui/mixins/_util.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/lib/sass/normalize-3.0.3.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/packages/npm/react.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/appbar.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/button.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/caret.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/checkbox.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/col.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/container.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/divider.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/dropdown-item.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/dropdown.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/form.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/input.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/panel.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/radio.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/row.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/select.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/angular/tabs.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email-inline.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email-styletag.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_body.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_buttons.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_containers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_divider.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_grid.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_helpers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_normalize.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_panel.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_reboot.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_styletag.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_typography.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/email/mui-email/_variables.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/config.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/dropdown.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/lib/forms.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/lib/jqLite.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/lib/util.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/overlay.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/ripple.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/select.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/tabs.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/js/textfield.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/_helpers.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/appbar.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/button.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/caret.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/checkbox.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/col.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/container.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/divider.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/dropdown-item.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/dropdown.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/form.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/input.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/option.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/panel.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/radio.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/row.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/select.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/tab.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/tabs.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/text-field.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/react/textarea.jsx create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui-colors.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_appbar.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_buttons.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_checkbox-and-radio.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_colors.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_containers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_divider.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_dropdown.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_form.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_grid.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_helpers.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_mixins.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_overlay.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_panel.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_reboot.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_ripple.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_select.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_table.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_tabs.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_textfield.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_typography.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/_variables.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/mixins/_buttons.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/mixins/_forms.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/mixins/_grid-framework.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/mixins/_typography.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/mui/mixins/_util.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/sass/normalize-3.0.3.scss create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/webcomponents/buttons.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/mui/src/webcomponents/forms.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/CHANGELOG.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/Gruntfile.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/LICENSE create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/package.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/src/notification.css create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/notification-js/src/notification.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/bower.json create mode 100755 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/build create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/package.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/sugar-date.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/sugarjs-date/sugar-date.min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/.bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/LICENSE create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/README.md create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/bower.json create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/underscore-min.js create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/underscore-min.map create mode 100644 mdot/mdot_server/mdot_server/src/bower_modules/underscore/underscore.js diff --git a/.DS_Store b/.DS_Store index 0c4d937c9db25cf4db5c2ef2ff12929d49308391..28e428ed7196a88dd66f81ebc2d6b220752f44a0 100644 GIT binary patch delta 162 zcmZoMXfc=|#>B)qu~2NHo+2aX#DLw4FEBDPa!xj26q&5RSRc*8kjs$5kk3$(lWrKC zoS$33fBB`mu~2NHo+2ab#DLw5tdk9xL?$aR)o { + logger.info('-=-=-=-=-'); + logger.info(socketSet.getClientStatus()); + heating_v1.setsocket(socketSet).subscribe(); + lighting_v1.setsocket(socketSet).subscribe(); + projector_v1.setsocket(socketSet).subscribe(); +}); + +busEmitter.on('clientStatusUpdated', (v) => { + logger.info(v); +}); + + + +logger.info('Configuring WebSocket Listener...'); +var server = http.createServer(function(request, response) { + logger.info((new Date()) + ' Received request for ' + request.url); + response.writeHead(404); + response.end(); +}); + +server.listen(3001, function() { + logger.info((new Date()) + ' Server is listening on port 3001'); +}); +var wsServer = new WebSocketServer({ + httpServer: server, // You should not use autoAcceptConnections for production + // applications, as it defeats all standard cross-origin protection + // facilities built into the protocol and the browser. You should + // *always* verify the connection's origin and decide whether or not + // to accept it. + autoAcceptConnections: false +}); + +function originIsAllowed(origin) { + // Put logic here to detect whether the specified origin is allowed. + return true; +} + +wsServer.on('request', function(request) { + + if (!originIsAllowed(request.origin)) { + // Make sure we only accept requests from an allowed origin + request.reject(); + logger.info((new Date()) + ' Connection from origin ' + request.origin + ' rejected.'); + return; + } + + var connection = request.accept('stream', request.origin); + logger.info((new Date()) + ' Connection accepted.'); + + var sendSocketHandler = (obj) => { + try { + connection.sendUTF(JSON.stringify(obj)); + } + catch (err) { + logger.error(err); + logger.warn('Offending object: ', obj); + } + }; + + busEmitter.on('sendSocket', sendSocketHandler); + + connection.on('message', function(message) { + if (message.type === 'utf8') { + logger.info('Received Message: ' + message.utf8Data); + connection.sendUTF(message.utf8Data); + } else if (message.type === 'binary') { + logger.info('Received Binary Message of ' + message.binaryData.length + ' bytes'); + connection.sendBytes(message.binaryData); + } + }); + + connection.on('close', function(reasonCode, description) { + logger.info((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); + busEmitter.removeListener('sendSocket', sendSocketHandler); + }); +}); + +mqttConnect.connectWS(function() { + logger.info('Ready to plug in sockets...'); +}); + +app.post('/api/v1/lighting/off', lighting_v1.turnoff); +app.post('/api/v1/lighting/on', lighting_v1.turnon); +app.post('/api/v1/lighting/cmd', lighting_v1.command); + +app.post('/api/v1/heating/off', heating_v1.turnoff); +app.post('/api/v1/heating/on', heating_v1.turnon); + +app.post('/api/v1/projector/off', projector_v1.turnoff); +app.post('/api/v1/projector/on', projector_v1.turnon); +app.post('/api/v1/projector/cmd', projector_v1.command); + +app.post('/api/v1/register/ios', function(req, res) { + + var body = req.body, registrationId; + + logger.debug(body); + + if (body.hasOwnProperty('registrationId')) { + registrationId = body['registrationId']; + logger.debug(registrationId); + + cal.registeriOSToken(registrationId); + + } +}); + +app.post('/api/v1/extend', function(req, res) { + + var body = req.body, data; + + if (body.hasOwnProperty('extendBy') && body.hasOwnProperty('uid')) { + data = req.body; + + cal.extendMeeting(data); + res.sendStatus(200); + } + +}); + +app.listen(3000, function() { + logger.info('Express listening on 3000'); + restartTimer(); +}); diff --git a/mdot/mdot_mqtt/mdot_mqtt/bower.json b/mdot/mdot_mqtt/mdot_mqtt/bower.json new file mode 100644 index 0000000..b0e93cc --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/bower.json @@ -0,0 +1,24 @@ +{ + "name": "sodashserver", + "description": "Smart Office Dashboard Server", + "main": "index.js", + "authors": [ + "Martin Donnelly" + ], + "license": "ISC", + "homepage": "", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "chroma-js": "^1.1.1", + "jquery": "^2.2.3", + "mui": "^0.5.3", + "sugarjs-date": "^1.5.1" + } +} diff --git a/mdot/mdot_mqtt/mdot_mqtt/gulpfile.js b/mdot/mdot_mqtt/mdot_mqtt/gulpfile.js new file mode 100644 index 0000000..01696c7 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/gulpfile.js @@ -0,0 +1,117 @@ +'use strict'; +var gulp = require('gulp'); +var autoprefixer = require('gulp-autoprefixer'); +var cssnano = require('gulp-cssnano'); +var jshint = require('gulp-jshint'); +var uglify = require('gulp-uglify'); +var jsmin = require('gulp-jsmin'); +var rename = require('gulp-rename'); +var concat = require('gulp-concat'); +var notify = require('gulp-notify'); +var cache = require('gulp-cache'); +var livereload = require('gulp-livereload'); +var htmlmin = require('gulp-htmlmin'); +var inject = require('gulp-inject'); +var del = require('del'); +var htmlreplace = require('gulp-html-replace'); +var googleWebFonts = require('gulp-google-webfonts'); + +var stripDebug = require('gulp-strip-debug'); +var size = require('gulp-size'); + +var debug = require('gulp-debug'); + +var filePath = { + build_dir: './dist' + }; + +gulp.task('scripts', function() { + return gulp.src(['app/js/sowebsocket.js','app/js/colours.js','app/js/appv2.js']) + .pipe(jshint('.jshintrc')) + .pipe(jshint.reporter('default')) + .pipe(concat('app.js')) + // .pipe(stripDebug()) + .pipe(jsmin()) + .pipe(size({title: 'Scripts'})) + .pipe(gulp.dest('dist/js')); + }); + +gulp.task('vendor', function() { + return gulp.src(['bower_components/jquery/dist/jquery.min.js', + 'bower_components/mui/packages/cdn/js/mui.min.js', + 'bower_components/chroma-js/chroma.min.js', + 'bower_components/sugar/release/sugar-full.min.js', + 'app/lib/skycons.js', + 'app/lib/microevent.js']) + .pipe(concat('vendor.js')) + .pipe(uglify({mangle: false})) + .pipe(size({title: 'Vendor'})) + .pipe(gulp.dest('dist/js')); + }); + + + + +gulp.task('styles', function() { + return gulp.src(['app/css/mui.custom.css','app/css/material-icons.css','app/css/app.css']) + .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4')) + .pipe(cssnano()) + .pipe(concat('app.css')) + .pipe(size({title: 'Styles'})) + .pipe(gulp.dest('dist/css')); + }); + +gulp.task('partials', function() { + + // Gulp.src(['app/partials/**/*']).pipe(gulp.dest('dist/partials')); + // gulp.src(['app/libs/ejs_production.js']).pipe(gulp.dest('dist/libs')); + // gulp.src(['app/libs/microevent.js']).pipe(gulp.dest('dist/libs')); + gulp.src(['app/fav/**/*']).pipe(size({title: 'Partials'})).pipe(gulp.dest('dist/fav')); + gulp.src(['app/gfx/censis_logo_white.png']).pipe(gulp.dest('dist/gfx')); +}); + +gulp.task('migrate', function() { + return gulp.src(['dist/**/*']) + .pipe(debug({title: 'migrate:'})) + .pipe(size({title: 'Migrate'})) + .pipe(gulp.dest('/Users/martin/newdev/SODashApp/www')); +}); + +gulp.task('index', function() { + var sources = gulp.src(['js/apps.js', 'css/app.css'], {read: false}); + + return gulp.src(['app/index.html']) + .pipe(htmlreplace({ + css: 'css/app.css', + js: 'js/app.js', + vendor: 'js/vendor.js', + fonts: 'fonts/fonts.css' + })) + .pipe(htmlmin({removeComments: true, collapseWhitespace: true, keepClosingSlash: true})) + .pipe(size({title: 'Index'})) + .pipe(gulp.dest('dist/')); + }); + +var options = { }; + +gulp.task('fonts', function() { + return gulp.src('./fonts.list') + .pipe(googleWebFonts(options)) + .pipe(size({title: 'Fonts'})) + .pipe(gulp.dest('dist/fonts')) + ; +}); + + +gulp.task('clean', function() { + return del(['dist']); + }); + + +gulp.task('default', ['clean'], function() { + gulp.start('styles', 'scripts', 'vendor', 'fonts', 'partials', 'index'); + }); + +gulp.task('Cordova', ['clean'], function() { + gulp.start('styles', 'scripts', 'vendor', 'fonts', 'index'); + }); diff --git a/mdot/mdot_mqtt/mdot_mqtt/index.js b/mdot/mdot_mqtt/mdot_mqtt/index.js new file mode 100644 index 0000000..15a73ae --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/index.js @@ -0,0 +1,28 @@ +var log4js = require('log4js'); +var logger = log4js.getLogger(); + + +var WebSocketServer = require('websocket').server; + +var EventEmitter = require('events'); +var busEmitter = new EventEmitter(); + + + +var mqttClient = require('./lib/mqtt/mqttClient'); +//var mqttSocket = require('./lib/mqtt/mqttSocket'); + + +//busEmitter.on('startWSConnection', startWSConnection); + +var mqtt = new mqttClient.mqttClient(busEmitter); + +/* + +mqttConnect.setEmitter(busEmitter); +mqttConnect.doConnection(); + + +mqttConnect.connectWS(); +*/ + diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/IoTFconnector.js b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/IoTFconnector.js new file mode 100644 index 0000000..146f228 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/IoTFconnector.js @@ -0,0 +1,130 @@ + + + +var IoTFconnector = function (orgId, api_key, auth_token, $rootScope) { + + + //this.connected = ''; + this.clientId = "a:" + orgId + ":" + Date.now(); + + console.log("clientId: " + this.clientId); + this.hostname = orgId + ".messaging.internetofthings.ibmcloud.com"; + this.client = ''; + + this.initialize = function () { + + client = new Messaging.Client(this.hostname, 8883, this.clientId); + + + client.onMessageArrived = function (msg) { + console.log("Message from :" + msg.destinationName); + }; + + var connectOptions = new Object(); + connectOptions.keepAliveInterval = 3600; + connectOptions.useSSL = true; + connectOptions.userName = api_key; + connectOptions.password = auth_token; + + connectOptions.onSuccess = function () { + IoTFconnector.prototype.clientStatus.connected = true; + // $rootScope.$broadcast("clientStatusUpdated", clientStatus); + console.log("MQTT connected to host: " + client.host + " port : " + client.port + " at " + Date.now()); + + } + + connectOptions.onFailure = function (e) { + console.log("MQTT connection failed at " + Date.now() + "\nerror: " + e.errorCode + " : " + e.errorMessage); + } + + console.log("about to connect to " + client.host); + client.connect(connectOptions); + + //client = new Messaging.Client(this.hostname, 8883, this.clientId); + + //// Initialize the Realtime Graph + ////var rtGraph = new RealtimeGraph(); + //client.onMessageArrived = function(msg) { + // //var topic = msg.destinationName; + + // //var payload = JSON.parse(msg.payloadString); + // ////First message, instantiate the graph + // //if (firstMessage) { + // // $('#chart').empty(); + // // firstMessage = false; + // // rtGraph.displayChart(null, payload); + // //} else { + // // rtGraph.graphData(payload); + // //} + // console.log("Message from :" + msg.destinationName); + //}; + + //client.onConnectionLost = function(e) { + // console.log("Connection Lost at " + Date.now() + " : " + e.errorCode + " : " + e.errorMessage); + // this.connect(connectOptions); + //} + + //var connectOptions = new Object(); + //connectOptions.keepAliveInterval = 3600; + //connectOptions.useSSL = true; + //connectOptions.userName = api_key; + //connectOptions.password = auth_token; + + //connectOptions.onSuccess = function() { + // IoTFconnector.prototype.connected = true; + // console.log("MQTT connected to host: " + client.host + " port : " + client.port + " at " + Date.now()); + + //} + + //connectOptions.onFailure = function(e) { + // console.log("MQTT connection failed at " + Date.now() + "\nerror: " + e.errorCode + " : " + e.errorMessage); + //} + + //console.log("about to connect to " + client.host); + //client.connect(connectOptions); + } + + + this.initialize(); + + //var imageHTML = '
The selected device is not currently sending events to the Internet of Things Foundation

Select to view historical data or select a different device.
Chart'; + +}; + + + + +IoTFconnector.prototype.clientStatus = { connected: false, subscribeTopic: '' };; + +IoTFconnector.prototype.disconnect = function disconnect() { + client.disconnect(); + console.log("Connection closed"); +} + +IoTFconnector.prototype.connect = function connect() { + // this.initialize(); +} + + + +IoTFconnector.prototype.subscribe = function subscribe(deviceId) { + var subscribeOptions = { + qos: 0, + onSuccess: function () { + console.log("subscribed to " + IoTFconnector.prototype.clientStatus.subscribeTopic); + }, + onFailure: function () { + console.log("Failed to subscribe to " + IoTFconnector.prototype.clientStatus.subscribeTopic); + console.log("As messages are not available, visualization is not possible"); + } + }; + + if (IoTFconnector.prototype.clientStatus.subscribeTopic != "") { + console.log("Unsubscribing to " + IoTFconnector.prototype.clientStatus.subscribeTopic); + client.unsubscribe(IoTFconnector.prototype.clientStatus.subscribeTopic); + }; + + IoTFconnector.prototype.clientStatus.subscribeTopic = "iot-2/type/iotsample-ti-cc3200/id/" + deviceId + "/evt/+/fmt/json"; + + client.subscribe(IoTFconnector.prototype.clientStatus.subscribeTopic, subscribeOptions); +} diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttClient.js b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttClient.js new file mode 100644 index 0000000..c5063b2 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttClient.js @@ -0,0 +1,157 @@ +var mqtt = require('mqtt'); +var request = require('request'); +var util = require('util'); +var logger = require('log4js').getLogger(); + +var EventEmitter = require('events'); + +//var nano = require('nano')('http://martind2000:1V3D4m526i@localhost:5984'); +var nano = require('nano')('http://localhost:5984'); +var busEmitter = new EventEmitter(); + +var db_name = 'mdot'; +var dbCouch = nano.use(db_name); + +var db = require('../server/db-connector').dbConnection; + +var dbSave = require('../server/db-save')(db); + + + +function dataBuilder(obj) { + 'use strict'; + var now = new Date(); + var newObj = {device_type: 'mDot', evt_type: 'update', timestamp: {}, evt: {}}; + + newObj.device_id = obj.topic.split('/')[4]; + + newObj.evt = obj; + newObj.timestamp['$date'] = now.getTime(); + + return newObj; +} + +function insertEntry(obj) { + + var newObj = dataBuilder(obj); + + logger.debug('Inserting into couch...'); + logger.info(util.inspect(newObj)); + dbCouch.insert(newObj, function(err, body, header) { + if (err) { + logger.error('Error inserting into couch'); + return; + } + }); + logger.debug('Insert done..'); +} + +var doInsertEntry = (obj) => { + // Logger.info('sendSocket: ' + JSON.stringify(obj)); + + var _rawObj = obj; + _rawObj.type = 1; + insertEntry(_rawObj); + + dbSave.addNewEvent(obj) + .then(function(d) { + 'use strict'; + console.log('Finished - Raw',d); + }) + .catch(function(e) { + 'use strict'; + console.error(e); + }); + + + dbSave.addProcessedEvent(obj) + .then(function(d) { + 'use strict'; + console.log('Finished - Processed',d); + }) + .catch(function(e) { + 'use strict'; + console.error(e); + }); +}; + + +var mqttClient = function() { + + var subscribeTopic; + var orgId = 'qz0da4'; + var userName = 'a-qz0da4-dfwwdkmkzr'; + var address = '.messaging.internetofthings.ibmcloud.com'; + var appKey = '9txJEf3Cjy7hkSOvkv'; + var prefix = 'iot-2/type/mDot/id/'; + var deviceId = ['CENSIS-LoRa-1','CENSIS-LoRa-2','CENSIS-LoRa-3','CENSIS-LoRa-4','HIE-mobile-1','HIE-demo','HIE-mobile-2','HIE-smart-campus-1','HIE-smart-campus-2','HIE-smart-campus-3','HIE-smart-campus-4','HIE-smart-campus-5','HIE-smart-campus-6','HIE-smart-campus-7','HIE-mDot-1']; + + + //Var subscribeTopic = prefix + deviceId + '/evt/+/fmt/json'; + + + this.connected = false; + + var options = { + keepalive: 3600, + clientId: 'a:' + orgId + ':' + Date.now(), + username: userName, + password: new Buffer(appKey) + + }; + + this.client = mqtt.connect('mqtt://' + orgId + address, options); + + this.client.on('connect', function() { + connected = true; + logger.info('Connected to ', address); + }.bind(this)); + + + for (var t = 0;t < deviceId.length;t++) { + subscribeTopic = prefix + deviceId[t] + '/evt/+/fmt/json'; + logger.info('Subscribing:', subscribeTopic); + this.client.subscribe(subscribeTopic); + } + + + + this.client.on('message', function(topic, message) { + console.log('onMessage',topic); + + var json = JSON.parse(message.toString()); + + json.topic = topic; + logger.debug(JSON.stringify(json)); + + busEmitter.emit('saveData', json); + + }.bind(this)); + + this.isConnected = function() { + + return this.connected; + }; + + this.client.on('connected', function() { + logger.debug('mqttConnect - doConnection - Connected'); + + }); + this.client.on('disconnect', function(e) { + logger.error('mqttConnect - doConnection - disconnect'); + logger.error(e); + }); + this.client.on('error', function(e) { + logger.error('mqttConnect - doConnection - disconnect'); + logger.error(e); + }); + + + busEmitter.on('saveData', doInsertEntry); + + + }; + + + +module.exports.mqttClient = mqttClient; diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttConnect.js b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttConnect.js new file mode 100644 index 0000000..75dd618 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttConnect.js @@ -0,0 +1,353 @@ +/** + * Created by Martin on 08/02/2016. + */ +'use strict'; +var mqtt = require('mqtt'); + +var Messaging = require('mqtt_over_websockets'); +var log4js = require('log4js'); +var logger = log4js.getLogger(); + +var mqttConfig = { + orgId: 'qz0da4', + userName: 'martind2000', + appKey: 'MPReoa43', + prefix: 'iot-2/type/Ti-CC3200/id/' + }; + +function randomString(length) { + return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1); +} + +/* + Projector: 'ProjectorISP15', + lighting: 'LightingISP15', + heating: 'HeatingISP15', + + */ +var live = true; + +logger.warn('!!! Live? ', live); +module.exports = { + restartTimer : 0, + pingTimer: 0, + statuses: {}, + sockets: null, + wsClient: null, + watches: {}, + client: null, + projector: live ? 'Projector' : 'ProjectorISP15', + lighting: live ? 'Lighting' : 'LightingISP15', + heating: live ? 'Heating' : 'HeatingISP15', + myID: 0, + connected: false, + options: { + // Keepalive: 3600, + keepalive: 60, + clientId: 'a:' + mqttConfig.orgId + ':' + Date.now(), + username: mqttConfig.userName, + password: new Buffer(mqttConfig.appKey) + + }, + lightList: {o: 'frontLight', f: 'frontLight',n: 'backLight', g: 'backLight'}, + updateStatus: function(id, packet) { + this.statuses[id] = packet; + logger.info('Statuses:', this.statuses); + }, + + setEmitter: function(newEmitter) { + this.emitter = newEmitter; + }, + doConnection: function(cb) { + console.log('Do connection'); + var self = this; + if (this.client === null) { + this.client = mqtt.connect('mqtt://' + 'silvrtree.co.uk', this.options); + + this.client.on('connect', function() { + logger.info('Connected to SilvrBroker'); + self.connected = this.connected; + }); + this.client.on('connected', function() { + logger.debug('mqttConnect - doConnection - Connected'); + + }); + this.client.on('disconnect', function(e) { + logger.error('mqttConnect - doConnection - disconnect'); + logger.error(e); + }); + this.client.on('error', function(e) { + logger.error('mqttConnect - doConnection - disconnect'); + logger.error(e); + }); + + } + return this; + }, + isConnected: function() { + return this.connected; + }, + sendCommand: function(deviceID, command) { + var payload = { + id: 'd', + text: command + + }; + }, + projectorOn: function(callback) { + var packet; + console.log('projectorOn:'); + var _callback = callback || {}; + + if (!this.client) { + return -1; + } + packet = {id: this.projector, status: true}; + var destinationName = mqttConfig.prefix + this.projector + '/cmd/' + 'ON' + '/fmt/json'; + this.client.publish(destinationName, 'ON', _callback); + this.emitter.emit('sendSocket',packet); + logger.debug('Storing status...'); + this.updateStatus('projector', packet); + }, + projectorOff: function(callback) { + var packet; + var _callback = callback || {}; + if (!this.client) { + return -1; + } + packet = {id: this.projector, status: false}; + var destinationName = mqttConfig.prefix + this.projector + '/cmd/' + 'OFF' + '/fmt/json'; + this.client.publish(destinationName, 'OFF', _callback); + this.emitter.emit('sendSocket',packet); + console.log('Storing status...'); + this.updateStatus('projector', packet); + + }, + projectorCmd: function(id, callback) { + var packet; + var _callback = callback || {}; + if (!this.client) { + return -1; + } + + var destinationName = mqttConfig.prefix + this.projector + '/cmd/' + id + '/fmt/json'; + this.client.publish(destinationName, 'cmd', _callback); + }, + heatingOn: function(callback) { + console.log('Turn heating on...'); + var _callback = callback || null; + if (!this.client) { + return -1; + } + var destinationName = mqttConfig.prefix + this.heating + '/cmd/' + 'on' + '/fmt/json'; + this.client.publish(destinationName, 'ON', _callback); + this.emitter.emit('sendSocket',{id: this.heating, status: true}); + }, + heatingOff: function(callback) { + var _callback = callback || {}; + if (!this.client) { + return -1; + } + var destinationName = mqttConfig.prefix + this.heating + '/cmd/' + 'off' + '/fmt/json'; + this.client.publish(destinationName, 'OFF', _callback); + this.emitter.emit('sendSocket',{id: this.heating, status: false}); + }, + lightingOn: function(id, callback) { + var packet; + + console.log('lightingOn:' + id); + var _callback = callback || null; + if (!this.client) { + return -1; + } + var destinationName = mqttConfig.prefix + this.lighting + '/cmd/' + id + '/fmt/json'; + this.client.publish(destinationName, 'ON', _callback); + packet = {id: this.lighting, device: id, status: true}; + this.emitter.emit('sendSocket',packet); + logger.debug('Storing status...'); + this.updateStatus(this.lightList[id], packet); + }, + lightingOff: function(id, callback) { + var packet; + var _callback = callback || null; + if (!this.client) { + return -1; + } + var destinationName = mqttConfig.prefix + this.lighting + '/cmd/' + id + '/fmt/json'; + this.client.publish(destinationName, 'OFF', _callback); + packet = {id: this.lighting, device: id, status: false}; + this.emitter.emit('sendSocket', packet); + this.updateStatus(this.lightList[id], packet); + }, + lightingCommand: function(id, callback) { + var packet; + var _callback = callback || null; + if (!this.client) { + return -1; + } + var destinationName = mqttConfig.prefix + this.lighting + '/cmd/' + id + '/fmt/json'; + this.client.publish(destinationName, 'cmd', _callback); + }, + + setupEvents: function() { + + this.emitter.on('lightingOn', this.lightingOn); + this.emitter.on('lightingOff', this.lightingOff); + this.emitter.on('heatingOn', this.heatingOn); + this.emitter.on('heatingOff', this.heatingOff); + this.emitter.on('projectorOn', this.projectorOn); + this.emitter.on('projectorOff', this.projectorOff); + }, + setupPing: function() { + logger.warn('Starting ping timer...'); + + this.pingTimer = setTimeout(function() {this.ping();}.bind(this), 10000); + }, + ping: function() { + //Logger.error('Ping!'); + this.sendRefresh(); + var now = new Date; + var mod = 10000 - (now.getTime() % 10000); + + setTimeout(function() {this.ping();}.bind(this),mod + 10); + + }, + sendRefresh: function() { + // logger.debug('+ Send refresh', this.statuses); + + for (var item in this.statuses) { + if (this.statuses.hasOwnProperty(item)) { + console.log(this.statuses[item]); + this.emitter.emit('sendSocket', this.statuses[item]); + } + } + // logger.debug('+ Send refresh'); + }, + preRestartConnection: function() { + logger.debug('Restart connection...'); + //this.emitter.emit('restartMQTTSocket', this); + //logger.debug(this); + this.restartMQTTSocket(); + }, + startMQTTSocket:function() { + logger.warn('Restarting socket?'); + this.connectWS(); + }, + restartMQTTSocket: function() { + this.wsClient.disconnect(); + // setTimeout(this.startMQTTSocket.bind(this), 15000); + }, + connectWS: function(connectCB) { + + logger.debug('Going to connect WS'); + var self = this; + var hostname = 'silvrtree.co.uk'; + var clientId = 'a:' + 'qz0da4' + ':' + Date.now(); + + var api_key = 'martind2000'; + var auth_token = 'MPReoa43'; + + this.wsClient =new Messaging.Client(hostname, 8883, clientId); + //var wsClient = new Messaging.Client(hostname, 8883, clientId); + var wsClient = this.wsClient; + var clientStatus = {connected: false, subscribed: false, deviceConnected: false}; + var sensorData = {}; + + + this.restartTimer = setTimeout(this.preRestartConnection.bind(this), 60000); + + wsClient.onMessageArrived = function(msg) { + //logger.info("Message from :" + msg.destinationName); + clearTimeout(self.restartTimer); + self.restartTimer = setTimeout(self.preRestartConnection.bind(self), 60000); + clientStatus.deviceConnected = true; + sensorData = JSON.parse(msg.payloadString); + // Logger.debug(sensorData); + var temp = msg.destinationName.split('/'); + if (self.watches.hasOwnProperty(temp[4])) { + + // Logger.info('Emit: ' + JSON.stringify({id:self.watches[temp[4]],sensorData:sensorData})); + + self.emitter.emit('sendSocket',{id: self.watches[temp[4]],sensorData: sensorData}); + } + + }; + wsClient.onConnectionLost = function(e) { + logger.error('+ wsClient.onConnectionLost'); + logger.error(e); + logger.warn('Going to force a restart of the Socket.. Hold on.'); + setTimeout(self.startMQTTSocket.bind(self), 15000); + //self.emitter.emit('sendSocket',{id: 'deviceLost',data: e}); + //var wsReconnectTimer = setTimeout(function() {logger.debug('TRYING TO RECONNECT TO MQTT');self.emitter.emit('connectWS');}.bind(this),30000); + logger.error('- wsClient.onConnectionLost'); + }; + + + var connectOptions = {}; + connectOptions.keepAliveInterval = 3600; + connectOptions.useSSL = true; + connectOptions.userName = api_key; + connectOptions.password = auth_token; + + connectOptions.onSuccess = function() { + clientStatus.connected = true; + logger.info('MQTT connected to host: ' + wsClient.host + ' port : ' + wsClient.port + ' at ' + Date.now()); + + self.emitter.emit('clientStatusUpdated', clientStatus); + self.emitter.emit('clientConnected', self.sockets); + }; + + connectOptions.onFailure = function(e) { + self.emitter.emit('sendSocket',{id: 'deviceNotConnecting'}); + logger.error('wsClient onFailure', e); + logger.error('MQTT connection failed at ' + Date.now() + '\nerror: ' + e.errorCode + ' : ' + e.errorMessage); + //var wsReconnectTimer = setTimeout(function() {logger.debug('TRYING TO RECONNECT TO MQTT');self.emitter.emit('connectWS');}.bind(this),30000); + }; + + logger.debug('about to connect to ' + wsClient.host); + wsClient.connect(connectOptions); + + this.sockets = { + + getClientStatus: function() { + return clientStatus; + }, + subscribe: function(deviceId, emitterId) { + logger.debug('trying to subscribe'); + var subscribeTopic = 'iot-2/type/Ti-CC3200/id/' + deviceId + '/evt/+/fmt/json'; + logger.debug(subscribeTopic); + + var subscribeOptions = { + qos: 0, + onSuccess: function() { + logger.info('subscribed to ' + subscribeTopic); + clientStatus.subscribed = true; + // $rootScope.$broadcast("clientStatusUpdated", clientStatus); + + self.emitter.emit('clientStatusUpdated', clientStatus); + self.watches[deviceId] = emitterId; + }, + onFailure: function() { + logger.error('Failed to subscribe to ' + subscribeTopic); + logger.error('As messages are not available, visualization is not possible'); + } + }; + + /*If (IoTFconnector.prototype.clientStatus.subscribeTopic != "") { + console.log("Unsubscribing to " + subscribeTopic); + wsClient.unsubscribe(IoTFconnector.prototype.clientStatus.subscribeTopic); + };*/ + + wsClient.subscribe(subscribeTopic, subscribeOptions); + } + }; + + + return this.sockets; + + } + + + }; + + diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttSocket.js b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttSocket.js new file mode 100644 index 0000000..4c784a0 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttSocket.js @@ -0,0 +1,7 @@ +/** + * + * User: Martin Donnelly + * Date: 2016-07-28 + * Time: 14:48 + * + */ diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttws31.js b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttws31.js new file mode 100644 index 0000000..a1eca98 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/mqtt/mqttws31.js @@ -0,0 +1,1791 @@ +"use strict"; +exports.Messaging = function (global) { + + // Private variables below, these are only visible inside the function closure + // which is used to define the module. + + var version = "0.0.0.0"; + var buildLevel = "p000-L130522.1"; + + /** + * Unique message type identifiers, with associated + * associated integer values. + * @private + */ + var MESSAGE_TYPE = { + CONNECT: 1, + CONNACK: 2, + PUBLISH: 3, + PUBACK: 4, + PUBREC: 5, + PUBREL: 6, + PUBCOMP: 7, + SUBSCRIBE: 8, + SUBACK: 9, + UNSUBSCRIBE: 10, + UNSUBACK: 11, + PINGREQ: 12, + PINGRESP: 13, + DISCONNECT: 14 + }; + + // Collection of utility methods used to simplify module code + // and promote the DRY pattern. + + /** + * Validate an object's parameter names to ensure they + * match a list of expected variables name for this option + * type. Used to ensure option object passed into the API don't + * contain erroneous parameters. + * @param {Object} obj User options object + * @param {key:type, key2:type, ...} valid keys and types that may exist in obj. + * @throws {Error} Invalid option parameter found. + * @private + */ + var validate = function(obj, keys) { + for(key in obj) { + if (obj.hasOwnProperty(key)) { + if (keys.hasOwnProperty(key)) { + if (typeof obj[key] !== keys[key]) + throw new Error(format(ERROR.INVALID_TYPE, [typeof obj[key], key])); + } else { + var errorStr = "Unknown property, " + key + ". Valid properties are:"; + for (key in keys) + if (keys.hasOwnProperty(key)) + errorStr = errorStr+" "+key; + throw new Error(errorStr); + } + } + } + }; + + /** + * Return a new function which runs the user function bound + * to a fixed scope. + * @param {function} User function + * @param {object} Function scope + * @return {function} User function bound to another scope + * @private + */ + var scope = function (f, scope) { + return function () { + return f.apply(scope, arguments); + }; + }; + + /** + * Unique message type identifiers, with associated + * associated integer values. + * @private + */ + var ERROR = { + OK: {code:0, text:"AMQJSC0000I OK."}, + CONNECT_TIMEOUT: {code:1, text:"AMQJSC0001E Connect timed out."}, + SUBSCRIBE_TIMEOUT: {code:2, text:"AMQJS0002E Subscribe timed out."}, + UNSUBSCRIBE_TIMEOUT: {code:3, text:"AMQJS0003E Unsubscribe timed out."}, + PING_TIMEOUT: {code:4, text:"AMQJS0004E Ping timed out."}, + INTERNAL_ERROR: {code:5, text:"AMQJS0005E Internal error."}, + CONNACK_RETURNCODE: {code:6, text:"AMQJS0006E Bad Connack return code:{0} {1}."}, + SOCKET_ERROR: {code:7, text:"AMQJS0007E Socket error:{0}."}, + SOCKET_CLOSE: {code:8, text:"AMQJS0008I Socket closed."}, + MALFORMED_UTF: {code:9, text:"AMQJS0009E Malformed UTF data:{0} {1} {2}."}, + UNSUPPORTED: {code:10, text:"AMQJS0010E {0} is not supported by this browser."}, + INVALID_STATE: {code:11, text:"AMQJS0011E Invalid state {0}."}, + INVALID_TYPE: {code:12, text:"AMQJS0012E Invalid type {0} for {1}."}, + INVALID_ARGUMENT: {code:13, text:"AMQJS0013E Invalid argument {0} for {1}."}, + UNSUPPORTED_OPERATION: {code:14, text:"AMQJS0014E Unsupported operation."}, + INVALID_STORED_DATA: {code:15, text:"AMQJS0015E Invalid data in local storage key={0} value={1}."}, + INVALID_MQTT_MESSAGE_TYPE: {code:16, text:"AMQJS0016E Invalid MQTT message type {0}."}, + MALFORMED_UNICODE: {code:17, text:"AMQJS0017E Malformed Unicode string:{0} {1}."}, + }; + + /** CONNACK RC Meaning. */ + var CONNACK_RC = { + 0:"Connection Accepted", + 1:"Connection Refused: unacceptable protocol version", + 2:"Connection Refused: identifier rejected", + 3:"Connection Refused: server unavailable", + 4:"Connection Refused: bad user name or password", + 5:"Connection Refused: not authorized" + }; + + /** + * Format an error message text. + * @private + * @param {error} ERROR.KEY value above. + * @param {substitutions} [array] substituted into the text. + * @return the text with the substitutions made. + */ + var format = function(error, substitutions) { + var text = error.text; + if (substitutions) { + for (var i=0; i 0) { + var part1 = text.substring(0,start); + var part2 = text.substring(start+field.length); + text = part1+substitutions[i]+part2; + } + } + } + return text; + }; + + //MQTT protocol and version 6 M Q I s d p 3 + var MqttProtoIdentifier = [0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70,0x03]; + + /** + * @ignore + * Construct an MQTT wire protocol message. + * @param type MQTT packet type. + * @param options optional wire message attributes. + * + * Optional properties + * + * messageIdentifier: message ID in the range [0..65535] + * payloadMessage: Application Message - PUBLISH only + * connectStrings: array of 0 or more Strings to be put into the CONNECT payload + * topics: array of strings (SUBSCRIBE, UNSUBSCRIBE) + * requestQoS: array of QoS values [0..2] + * + * "Flag" properties + * cleanSession: true if present / false if absent (CONNECT) + * willMessage: true if present / false if absent (CONNECT) + * isRetained: true if present / false if absent (CONNECT) + * userName: true if present / false if absent (CONNECT) + * password: true if present / false if absent (CONNECT) + * keepAliveInterval: integer [0..65535] (CONNECT) + * + * @private + */ + var WireMessage = function (type, options) { + this.type = type; + for(name in options) { + if (options.hasOwnProperty(name)) { + this[name] = options[name]; + } + } + }; + + WireMessage.prototype.encode = function() { + // Compute the first byte of the fixed header + var first = ((this.type & 0x0f) << 4); + + /* + * Now calculate the length of the variable header + payload by adding up the lengths + * of all the component parts + */ + + remLength = 0; + topicStrLength = new Array(); + + // if the message contains a messageIdentifier then we need two bytes for that + if (this.messageIdentifier != undefined) + remLength += 2; + + switch(this.type) { + // If this a Connect then we need to include 12 bytes for its header + case MESSAGE_TYPE.CONNECT: + remLength += MqttProtoIdentifier.length + 3; + remLength += UTF8Length(this.clientId) + 2; + if (this.willMessage != undefined) { + remLength += UTF8Length(this.willMessage.destinationName) + 2; + // Will message is always a string, sent as UTF-8 characters with a preceding length. + var willMessagePayloadBytes = this.willMessage.payloadBytes; + if (!(willMessagePayloadBytes instanceof Uint8Array)) + willMessagePayloadBytes = new Uint8Array(payloadBytes); + remLength += willMessagePayloadBytes.byteLength +2; + } + if (this.userName != undefined) + remLength += UTF8Length(this.userName) + 2; + if (this.password != undefined) + remLength += UTF8Length(this.password) + 2; + break; + + // Subscribe, Unsubscribe can both contain topic strings + case MESSAGE_TYPE.SUBSCRIBE: + first |= 0x02; // Qos = 1; + for ( var i = 0; i < this.topics.length; i++) { + topicStrLength[i] = UTF8Length(this.topics[i]); + remLength += topicStrLength[i] + 2; + } + remLength += this.requestedQos.length; // 1 byte for each topic's Qos + // QoS on Subscribe only + break; + + case MESSAGE_TYPE.UNSUBSCRIBE: + first |= 0x02; // Qos = 1; + for ( var i = 0; i < this.topics.length; i++) { + topicStrLength[i] = UTF8Length(this.topics[i]); + remLength += topicStrLength[i] + 2; + } + break; + + case MESSAGE_TYPE.PUBLISH: + if (this.payloadMessage.duplicate) first |= 0x08; + first = first |= (this.payloadMessage.qos << 1); + if (this.payloadMessage.retained) first |= 0x01; + destinationNameLength = UTF8Length(this.payloadMessage.destinationName); + remLength += destinationNameLength + 2; + var payloadBytes = this.payloadMessage.payloadBytes; + remLength += payloadBytes.byteLength; + if (payloadBytes instanceof ArrayBuffer) + payloadBytes = new Uint8Array(payloadBytes); + else if (!(payloadBytes instanceof Uint8Array)) + payloadBytes = new Uint8Array(payloadBytes.buffer); + break; + + case MESSAGE_TYPE.DISCONNECT: + break; + + default: + ; + } + + // Now we can allocate a buffer for the message + + var mbi = encodeMBI(remLength); // Convert the length to MQTT MBI format + var pos = mbi.length + 1; // Offset of start of variable header + var buffer = new ArrayBuffer(remLength + pos); + var byteStream = new Uint8Array(buffer); // view it as a sequence of bytes + + //Write the fixed header into the buffer + byteStream[0] = first; + byteStream.set(mbi,1); + + // If this is a PUBLISH then the variable header starts with a topic + if (this.type == MESSAGE_TYPE.PUBLISH) + pos = writeString(this.payloadMessage.destinationName, destinationNameLength, byteStream, pos); + // If this is a CONNECT then the variable header contains the protocol name/version, flags and keepalive time + + else if (this.type == MESSAGE_TYPE.CONNECT) { + byteStream.set(MqttProtoIdentifier, pos); + pos += MqttProtoIdentifier.length; + var connectFlags = 0; + if (this.cleanSession) + connectFlags = 0x02; + if (this.willMessage != undefined ) { + connectFlags |= 0x04; + connectFlags |= (this.willMessage.qos<<3); + if (this.willMessage.retained) { + connectFlags |= 0x20; + } + } + if (this.userName != undefined) + connectFlags |= 0x80; + if (this.password != undefined) + connectFlags |= 0x40; + byteStream[pos++] = connectFlags; + pos = writeUint16 (this.keepAliveInterval, byteStream, pos); + } + + // Output the messageIdentifier - if there is one + if (this.messageIdentifier != undefined) + pos = writeUint16 (this.messageIdentifier, byteStream, pos); + + switch(this.type) { + case MESSAGE_TYPE.CONNECT: + pos = writeString(this.clientId, UTF8Length(this.clientId), byteStream, pos); + if (this.willMessage != undefined) { + pos = writeString(this.willMessage.destinationName, UTF8Length(this.willMessage.destinationName), byteStream, pos); + pos = writeUint16(willMessagePayloadBytes.byteLength, byteStream, pos); + byteStream.set(willMessagePayloadBytes, pos); + pos += willMessagePayloadBytes.byteLength; + + } + if (this.userName != undefined) + pos = writeString(this.userName, UTF8Length(this.userName), byteStream, pos); + if (this.password != undefined) + pos = writeString(this.password, UTF8Length(this.password), byteStream, pos); + break; + + case MESSAGE_TYPE.PUBLISH: + // PUBLISH has a text or binary payload, if text do not add a 2 byte length field, just the UTF characters. + byteStream.set(payloadBytes, pos); + + break; + +// case MESSAGE_TYPE.PUBREC: +// case MESSAGE_TYPE.PUBREL: +// case MESSAGE_TYPE.PUBCOMP: +// break; + + case MESSAGE_TYPE.SUBSCRIBE: + // SUBSCRIBE has a list of topic strings and request QoS + for (var i=0; i> 4; + var messageInfo = first &= 0x0f; + var pos = 1; + + + // Decode the remaining length (MBI format) + + var digit; + var remLength = 0; + var multiplier = 1; + do { + digit = input[pos++]; + remLength += ((digit & 0x7F) * multiplier); + multiplier *= 128; + } while ((digit & 0x80) != 0); + + var wireMessage = new WireMessage(type); + switch(type) { + case MESSAGE_TYPE.CONNACK: + wireMessage.topicNameCompressionResponse = input[pos++]; + wireMessage.returnCode = input[pos++]; + break; + + case MESSAGE_TYPE.PUBLISH: + var qos = (messageInfo >> 1) & 0x03; + + var len = readUint16(input, pos); + pos += 2; + var topicName = parseUTF8(input, pos, len); + pos += len; + // If QoS 1 or 2 there will be a messageIdentifier + if (qos > 0) { + wireMessage.messageIdentifier = readUint16(input, pos); + pos += 2; + } + + var message = new Messaging.Message(input.subarray(pos)); + if ((messageInfo & 0x01) == 0x01) + message.retained = true; + if ((messageInfo & 0x08) == 0x08) + message.duplicate = true; + message.qos = qos; + message.destinationName = topicName; + wireMessage.payloadMessage = message; + break; + + case MESSAGE_TYPE.PUBACK: + case MESSAGE_TYPE.PUBREC: + case MESSAGE_TYPE.PUBREL: + case MESSAGE_TYPE.PUBCOMP: + case MESSAGE_TYPE.UNSUBACK: + wireMessage.messageIdentifier = readUint16(input, pos); + break; + + case MESSAGE_TYPE.SUBACK: + wireMessage.messageIdentifier = readUint16(input, pos); + pos += 2; + wireMessage.grantedQos = input.subarray(pos); + break; + + default: + ; + } + + return wireMessage; + } + + function writeUint16(input, buffer, offset) { + buffer[offset++] = input >> 8; //MSB + buffer[offset++] = input % 256; //LSB + return offset; + } + + function writeString(input, utf8Length, buffer, offset) { + offset = writeUint16(utf8Length, buffer, offset); + stringToUTF8(input, buffer, offset); + return offset + utf8Length; + } + + function readUint16(buffer, offset) { + return 256*buffer[offset] + buffer[offset+1]; + } + + /** + * Encodes an MQTT Multi-Byte Integer + * @private + */ + function encodeMBI(number) { + var output = new Array(1); + var numBytes = 0; + + do { + var digit = number % 128; + number = number >> 7; + if (number > 0) { + digit |= 0x80; + } + output[numBytes++] = digit; + } while ( (number > 0) && (numBytes<4) ); + + return output; + } + + /** + * Takes a String and calculates its length in bytes when encoded in UTF8. + * @private + */ + function UTF8Length(input) { + var output = 0; + for (var i = 0; i 0x7FF) + { + // Surrogate pair means its a 4 byte character + if (0xD800 <= charCode && charCode <= 0xDBFF) + { + i++; + output++; + } + output +=3; + } + else if (charCode > 0x7F) + output +=2; + else + output++; + } + return output; + } + + /** + * Takes a String and writes it into an array as UTF8 encoded bytes. + * @private + */ + function stringToUTF8(input, output, start) { + var pos = start; + for (var i = 0; i>6 & 0x1F | 0xC0; + output[pos++] = charCode & 0x3F | 0x80; + } else if (charCode <= 0xFFFF) { + output[pos++] = charCode>>12 & 0x0F | 0xE0; + output[pos++] = charCode>>6 & 0x3F | 0x80; + output[pos++] = charCode & 0x3F | 0x80; + } else { + output[pos++] = charCode>>18 & 0x07 | 0xF0; + output[pos++] = charCode>>12 & 0x3F | 0x80; + output[pos++] = charCode>>6 & 0x3F | 0x80; + output[pos++] = charCode & 0x3F | 0x80; + }; + } + return output; + } + + function parseUTF8(input, offset, length) { + var output = ""; + var utf16; + var pos = offset; + + while (pos < offset+length) + { + var byte1 = input[pos++]; + if (byte1 < 128) + utf16 = byte1; + else + { + var byte2 = input[pos++]-128; + if (byte2 < 0) + throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16),""])); + if (byte1 < 0xE0) // 2 byte character + utf16 = 64*(byte1-0xC0) + byte2; + else + { + var byte3 = input[pos++]-128; + if (byte3 < 0) + throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16)])); + if (byte1 < 0xF0) // 3 byte character + utf16 = 4096*(byte1-0xE0) + 64*byte2 + byte3; + else + { + var byte4 = input[pos++]-128; + if (byte4 < 0) + throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)])); + if (byte1 < 0xF8) // 4 byte character + utf16 = 262144*(byte1-0xF0) + 4096*byte2 + 64*byte3 + byte4; + else // longer encodings are not supported + throw new Error(format(ERROR.MALFORMED_UTF, [byte1.toString(16), byte2.toString(16), byte3.toString(16), byte4.toString(16)])); + } + } + } + + if (utf16 > 0xFFFF) // 4 byte character - express as a surrogate pair + { + utf16 -= 0x10000; + output += String.fromCharCode(0xD800 + (utf16 >> 10)); // lead character + utf16 = 0xDC00 + (utf16 & 0x3FF); // trail character + } + output += String.fromCharCode(utf16); + } + return output; + } + + /** @ignore Repeat keepalive requests, monitor responses.*/ + var Pinger = function(client, window, keepAliveInterval) { + this._client = client; + this._window = window; + this._keepAliveInterval = keepAliveInterval*1000; + this.isReset = false; + + var pingReq = new WireMessage(MESSAGE_TYPE.PINGREQ).encode(); + + var doTimeout = function (pinger) { + return function () { + return doPing.apply(pinger); + }; + }; + + /** @ignore */ + var doPing = function() { + if (!this.isReset) { + this._client._trace("Pinger.doPing", "Timed out"); + this._client._disconnected( ERROR.PING_TIMEOUT.code , format(ERROR.PING_TIMEOUT)); + } else { + this.isReset = false; + this._client._trace("Pinger.doPing", "send PINGREQ"); + this._client.socket.send(pingReq); + this.timeout = this._window.setTimeout(doTimeout(this), this._keepAliveInterval); + } + } + + this.reset = function() { + this.isReset = true; + this._window.clearTimeout(this.timeout); + if (this._keepAliveInterval > 0) + this.timeout = setTimeout(doTimeout(this), this._keepAliveInterval); + } + + this.cancel = function() { + this._window.clearTimeout(this.timeout); + } + }; + + /** @ignore Monitor request completion. */ + var Timeout = function(client, window, timeoutSeconds, action, args) { + this._window = window; + if (!timeoutSeconds) + timeoutSeconds = 30; + + var doTimeout = function (action, client, args) { + return function () { + return action.apply(client, args); + }; + }; + this.timeout = setTimeout(doTimeout(action, client, args), timeoutSeconds * 1000); + + this.cancel = function() { + this._window.clearTimeout(this.timeout); + } + }; + + /* + * Internal implementation of the Websockets MQTT V3.1 client. + * + * @name Messaging.ClientImpl @constructor + * @param {String} host the DNS nameof the webSocket host. + * @param {Number} port the port number for that host. + * @param {String} clientId the MQ client identifier. + */ + var ClientImpl = function (host, port, clientId) { + // Check dependencies are satisfied in this browser. + if (!("WebSocket" in global && global["WebSocket"] !== null)) { + throw new Error(format(ERROR.UNSUPPORTED, ["WebSocket"])); + } + if (!("localStorage" in global && global["localStorage"] !== null)) { + throw new Error(format(ERROR.UNSUPPORTED, ["localStorage"])); + } + if (!("ArrayBuffer" in global && global["ArrayBuffer"] !== null)) { + throw new Error(format(ERROR.UNSUPPORTED, ["ArrayBuffer"])); + } + + this._trace("Messaging.Client", host, port, clientId); + + this.host = host; + this.port = port; + this.clientId = clientId; + + // Local storagekeys are qualified with the following string. + this._localKey=host+":"+port+":"+clientId+":"; + + // Create private instance-only message queue + // Internal queue of messages to be sent, in sending order. + this._msg_queue = []; + + // Messages we have sent and are expecting a response for, indexed by their respective message ids. + this._sentMessages = {}; + + // Messages we have received and acknowleged and are expecting a confirm message for + // indexed by their respective message ids. + this._receivedMessages = {}; + + // Internal list of callbacks to be executed when messages + // have been successfully sent over web socket, e.g. disconnect + // when it doesn't have to wait for ACK, just message is dispatched. + this._notify_msg_sent = {}; + + // Unique identifier for SEND messages, incrementing + // counter as messages are sent. + this._message_identifier = 1; + + // Used to determine the transmission sequence of stored sent messages. + this._sequence = 0; + + + // Load the local state, if any, from the saved version, only restore state relevant to this client. + for(key in localStorage) + if ( key.indexOf("Sent:"+this._localKey) == 0 + || key.indexOf("Received:"+this._localKey) == 0) + this.restore(key); + }; + + // Messaging Client public instance members. + ClientImpl.prototype.host; + ClientImpl.prototype.port; + ClientImpl.prototype.clientId; + + // Messaging Client private instance members. + ClientImpl.prototype.socket; + /* true once we have received an acknowledgement to a CONNECT packet. */ + ClientImpl.prototype.connected = false; + /* The largest message identifier allowed, may not be larger than 2**16 but + * if set smaller reduces the maximum number of outbound messages allowed. + */ + ClientImpl.prototype.maxMessageIdentifier = 65536; + ClientImpl.prototype.connectOptions; + ClientImpl.prototype.hostIndex; + ClientImpl.prototype.onConnectionLost; + ClientImpl.prototype.onMessageDelivered; + ClientImpl.prototype.onMessageArrived; + ClientImpl.prototype._msg_queue = null; + ClientImpl.prototype._connectTimeout; + /* Send keep alive messages. */ + ClientImpl.prototype.pinger = null; + + ClientImpl.prototype._traceBuffer = null; + ClientImpl.prototype._MAX_TRACE_ENTRIES = 100; + + ClientImpl.prototype.connect = function (connectOptions) { + var connectOptionsMasked = this._traceMask(connectOptions, "password"); + this._trace("Client.connect", connectOptionsMasked, this.socket, this.connected); + + if (this.connected) + throw new Error(format(ERROR.INVALID_STATE, ["already connected"])); + if (this.socket) + throw new Error(format(ERROR.INVALID_STATE, ["already connected"])); + + this.connectOptions = connectOptions; + + if (connectOptions.hosts) { + this.hostIndex = 0; + this._doConnect(connectOptions.hosts[0], connectOptions.ports[0]); + } else { + this._doConnect(this.host, this.port); + } + + }; + + ClientImpl.prototype.subscribe = function (filter, subscribeOptions) { + this._trace("Client.subscribe", filter, subscribeOptions); + + if (!this.connected) + throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); + + var wireMessage = new WireMessage(MESSAGE_TYPE.SUBSCRIBE); + wireMessage.topics=[filter]; + if (subscribeOptions.qos != undefined) + wireMessage.requestedQos = [subscribeOptions.qos]; + else + wireMessage.requestedQos = [0]; + + if (subscribeOptions.onSuccess) { + wireMessage.callback = function() {subscribeOptions.onSuccess({invocationContext:subscribeOptions.invocationContext});}; + } + if (subscribeOptions.timeout) { + wireMessage.timeOut = new Timeout(this, window, subscribeOptions.timeout, subscribeOptions.onFailure + , [{invocationContext:subscribeOptions.invocationContext, + errorCode:ERROR.SUBSCRIBE_TIMEOUT.code, + errorMessage:format(ERROR.SUBSCRIBE_TIMEOUT)}]); + } + + // All subscriptions return a SUBACK. + this._requires_ack(wireMessage); + this._schedule_message(wireMessage); + }; + + /** @ignore */ + ClientImpl.prototype.unsubscribe = function(filter, unsubscribeOptions) { + this._trace("Client.unsubscribe", filter, unsubscribeOptions); + + if (!this.connected) + throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); + + var wireMessage = new WireMessage(MESSAGE_TYPE.UNSUBSCRIBE); + wireMessage.topics = [filter]; + + if (unsubscribeOptions.onSuccess) { + wireMessage.callback = function() {unsubscribeOptions.onSuccess({invocationContext:unsubscribeOptions.invocationContext});}; + } + if (unsubscribeOptions.timeout) { + wireMessage.timeOut = new Timeout(this, window, unsubscribeOptions.timeout, unsubscribeOptions.onFailure + , [{invocationContext:unsubscribeOptions.invocationContext, + errorCode:ERROR.UNSUBSCRIBE_TIMEOUT.code, + errorMessage:format(ERROR.UNSUBSCRIBE_TIMEOUT)}]); + } + + // All unsubscribes return a SUBACK. + this._requires_ack(wireMessage); + this._schedule_message(wireMessage); + }; + + ClientImpl.prototype.send = function (message) { + this._trace("Client.send", message); + + if (!this.connected) + throw new Error(format(ERROR.INVALID_STATE, ["not connected"])); + + wireMessage = new WireMessage(MESSAGE_TYPE.PUBLISH); + wireMessage.payloadMessage = message; + + if (message.qos > 0) + this._requires_ack(wireMessage); + else if (this.onMessageDelivered) + this._notify_msg_sent[wireMessage] = this.onMessageDelivered(wireMessage.payloadMessage); + this._schedule_message(wireMessage); + }; + + ClientImpl.prototype.disconnect = function () { + this._trace("Client.disconnect"); + + if (!this.socket) + throw new Error(format(ERROR.INVALID_STATE, ["not connecting or connected"])); + + wireMessage = new WireMessage(MESSAGE_TYPE.DISCONNECT); + + // Run the disconnected call back as soon as the message has been sent, + // in case of a failure later on in the disconnect processing. + // as a consequence, the _disconected call back may be run several times. + this._notify_msg_sent[wireMessage] = scope(this._disconnected, this); + + this._schedule_message(wireMessage); + }; + + ClientImpl.prototype.getTraceLog = function () { + if ( this._traceBuffer !== null ) { + this._trace("Client.getTraceLog", new Date()); + this._trace("Client.getTraceLog in flight messages", this._sentMessages.length); + for (key in this._sentMessages) + this._trace("_sentMessages ",key, this._sentMessages[key]); + for (key in this._receivedMessages) + this._trace("_receivedMessages ",key, this._receivedMessages[key]); + + return this._traceBuffer; + } + }; + + ClientImpl.prototype.startTrace = function () { + if ( this._traceBuffer === null ) { + this._traceBuffer = []; + } + this._trace("Client.startTrace", new Date(), version); + }; + + ClientImpl.prototype.stopTrace = function () { + delete this._traceBuffer; + }; + + ClientImpl.prototype._doConnect = function (host, port) { + // When the socket is open, this client will send the CONNECT WireMessage using the saved parameters. + if (this.connectOptions.useSSL) + wsurl = ["wss://", host, ":", port, "/mqtt"].join(""); + else + wsurl = ["ws://", host, ":", port, "/mqtt"].join(""); + this.connected = false; + this.socket = new WebSocket(wsurl, 'mqttv3.1'); + this.socket.binaryType = 'arraybuffer'; + this.socket.onopen = scope(this._on_socket_open, this); + this.socket.onmessage = scope(this._on_socket_message, this); + this.socket.onerror = scope(this._on_socket_error, this); + this.socket.onclose = scope(this._on_socket_close, this); + + this.pinger = new Pinger(this, window, this.connectOptions.keepAliveInterval); + + this._connectTimeout = new Timeout(this, window, this.connectOptions.timeout, this._disconnected, [ERROR.CONNECT_TIMEOUT.code, format(ERROR.CONNECT_TIMEOUT)]); + }; + + + // Schedule a new message to be sent over the WebSockets + // connection. CONNECT messages cause WebSocket connection + // to be started. All other messages are queued internally + // until this has happened. When WS connection starts, process + // all outstanding messages. + ClientImpl.prototype._schedule_message = function (message) { + this._msg_queue.push(message); + // Process outstanding messages in the queue if we have an open socket, and have received CONNACK. + if (this.connected) { + this._process_queue(); + } + }; + + ClientImpl.prototype.store = function(prefix, wireMessage) { + storedMessage = {type:wireMessage.type, messageIdentifier:wireMessage.messageIdentifier, version:1}; + + switch(wireMessage.type) { + case MESSAGE_TYPE.PUBLISH: + if(wireMessage.pubRecReceived) + storedMessage.pubRecReceived = true; + + // Convert the payload to a hex string. + storedMessage.payloadMessage = {}; + var hex = ""; + var messageBytes = wireMessage.payloadMessage.payloadBytes; + for (var i=0; i= 2) { + var x = parseInt(hex.substring(0, 2), 16); + hex = hex.substring(2, hex.length); + byteStream[i++] = x; + } + var payloadMessage = new Messaging.Message(byteStream); + + payloadMessage.qos = storedMessage.payloadMessage.qos; + payloadMessage.destinationName = storedMessage.payloadMessage.destinationName; + if (storedMessage.payloadMessage.duplicate) + payloadMessage.duplicate = true; + if (storedMessage.payloadMessage.retained) + payloadMessage.retained = true; + wireMessage.payloadMessage = payloadMessage; + + break; + + default: + throw Error(format(ERROR.INVALID_STORED_DATA, [key, value])); + } + + if (key.indexOf("Sent:"+this._localKey) == 0) { + this._sentMessages[wireMessage.messageIdentifier] = wireMessage; + } else if (key.indexOf("Received:"+this._localKey) == 0) { + this._receivedMessages[wireMessage.messageIdentifier] = wireMessage; + } + }; + + ClientImpl.prototype._process_queue = function () { + var message = null; + // Process messages in order they were added + var fifo = this._msg_queue.reverse(); + + // Send all queued messages down socket connection + while ((message = fifo.pop())) { + this._socket_send(message); + // Notify listeners that message was successfully sent + if (this._notify_msg_sent[message]) { + this._notify_msg_sent[message](); + delete this._notify_msg_sent[message]; + } + } + }; + + /** + * @ignore + * Expect an ACK response for this message. Add message to the set of in progress + * messages and set an unused identifier in this message. + */ + ClientImpl.prototype._requires_ack = function (wireMessage) { + var messageCount = Object.keys(this._sentMessages).length; + if (messageCount > this.maxMessageIdentifier) + throw Error ("Too many messages:"+messageCount); + + while(this._sentMessages[this._message_identifier] !== undefined) { + this._message_identifier++; + } + wireMessage.messageIdentifier = this._message_identifier; + this._sentMessages[wireMessage.messageIdentifier] = wireMessage; + if (wireMessage.type === MESSAGE_TYPE.PUBLISH) { + this.store("Sent:", wireMessage); + } + if (this._message_identifier === this.maxMessagIdentifier) { + this._message_identifier = 1; + } + }; + + /** + * @ignore + * Called when the underlying websocket has been opened. + */ + ClientImpl.prototype._on_socket_open = function () { + // Create the CONNECT message object. + var wireMessage = new WireMessage(MESSAGE_TYPE.CONNECT, this.connectOptions); + wireMessage.clientId = this.clientId; + this._socket_send(wireMessage); + }; + + /** + * @ignore + * Called when the underlying websocket has received a complete packet. + */ + ClientImpl.prototype._on_socket_message = function (event) { + this._trace("Client._on_socket_message", event.data); + + // Reset the ping timer. + this.pinger.reset(); + var byteArray = new Uint8Array(event.data); + try { + var wireMessage = decodeMessage(byteArray); + } catch (error) { + this._disconnected(ERROR.INTERNAL_ERROR.code , format(ERROR.INTERNAL_ERROR, [error.message])); + return; + } + this._trace("Client._on_socket_message", wireMessage); + + switch(wireMessage.type) { + case MESSAGE_TYPE.CONNACK: + this._connectTimeout.cancel(); + + // If we have started using clean session then clear up the local state. + if (this.connectOptions.cleanSession) { + for (key in this._sentMessages) { + var sentMessage = this._sentMessages[key]; + localStorage.removeItem("Sent:"+this._localKey+sentMessage.messageIdentifier); + } + this._sentMessages = {}; + + for (key in this._receivedMessages) { + var receivedMessage = this._receivedMessages[key]; + localStorage.removeItem("Received:"+this._localKey+receivedMessage.messageIdentifier); + } + this._receivedMessages = {}; + } + // Client connected and ready for business. + if (wireMessage.returnCode === 0) { + this.connected = true; + // Jump to the end of the list of hosts and stop looking for a good host. + if (this.connectOptions.hosts) + this.hostIndex = this.connectOptions.hosts.length; + } else { + this._disconnected(ERROR.CONNACK_RETURNCODE.code , format(ERROR.CONNACK_RETURNCODE, [wireMessage.returnCode, CONNACK_RC[wireMessage.returnCode]])); + break; + } + + // Resend messages. + var sequencedMessages = new Array(); + for (var msgId in this._sentMessages) { + if (this._sentMessages.hasOwnProperty(msgId)) + sequencedMessages.push(this._sentMessages[msgId]); + } + + // Sort sentMessages into the original sent order. + var sequencedMessages = sequencedMessages.sort(function(a,b) {return a.sequence - b.sequence;} ); + for (var i=0, len=sequencedMessages.length; i + * Other programming languages, + * Java, + * C. + *

+ * Most applications will create just one Client object and then call its connect() method, + * however applications can create more than one Client object if they wish. + * In this case the combination of host, port and clientId attributes must be different for each Client object. + *

+ * The send, subscribe and unsubscribe methods are implemented as asynchronous JavaScript methods + * (even though the underlying protocol exchange might be synchronous in nature). + * This means they signal their completion by calling back to the application, + * via Success or Failure callback functions provided by the application on the method in question. + * Such callbacks are called at most once per method invocation and do not persist beyond the lifetime + * of the script that made the invocation. + *

+ * In contrast there are some callback functions most notably onMessageArrived + * that are defined on the Messaging.Client object. + * These may get called multiple times, and aren't directly related to specific method invocations made by the client. + * + * @name Messaging.Client + * + * @constructor + * Creates a Messaging.Client object that can be used to communicate with a Messaging server. + * + * @param {string} host the address of the messaging server, as a DNS name or dotted decimal IP address. + * @param {number} port the port number in the host to connect to. + * @param {string} clientId the Messaging client identifier, between 1 and 23 characters in length. + * + * @property {string} host read only the server's DNS hostname or dotted decimal IP address. + * @property {number} port read only the server's port. + * @property {string} clientId read only used when connecting to the server. + * @property {function} onConnectionLost called when a connection has been lost, + * after a connect() method has succeeded. + * Establish the call back used when a connection has been lost. The connection may be + * lost because the client initiates a disconnect or because the server or network + * cause the client to be disconnected. The disconnect call back may be called without + * the connectionComplete call back being invoked if, for example the client fails to + * connect. + * A single response object parameter is passed to the onConnectionLost callback containing the following fields: + *

    + *
  1. errorCode + *
  2. errorMessage + *
+ * @property {function} onMessageDelivered called when a message has been delivered. + * All processing that this Client will ever do has been completed. So, for example, + * in the case of a Qos=2 message sent by this client, the PubComp flow has been received from the server + * and the message has been removed from persistent storage before this callback is invoked. + * Parameters passed to the onMessageDelivered callback are: + *
    + *
  1. Messaging.Message that was delivered. + *
+ * @property {function} onMessageArrived called when a message has arrived in this Messaging.client. + * Parameters passed to the onMessageArrived callback are: + *
    + *
  1. Messaging.Message that has arrived. + *
+ */ + var Client = function (host, port, clientId) { + if (typeof host !== "string") + throw new Error(format(ERROR.INVALID_TYPE, [typeof host, "host"])); + if (typeof port !== "number" || port < 0) + throw new Error(format(ERROR.INVALID_TYPE, [typeof port, "port"])); + + var clientIdLength = 0; + for (var i = 0; i 23) + throw new Error(format(ERROR.INVALID_ARGUMENT, [clientId, "clientId"])); + + var client = new ClientImpl(host, port, clientId); + this._getHost = function() { return client.host; }; + this._setHost = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; + + this._getPort = function() { return client.port; }; + this._setPort = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; + + this._getClientId = function() { return client.clientId; }; + this._setClientId = function() { throw new Error(format(ERROR.UNSUPPORTED_OPERATION)); }; + + this._getOnConnectionLost = function() { return client.onConnectionLost; }; + this._setOnConnectionLost = function(newOnConnectionLost) { + if (typeof newOnConnectionLost === "function") + client.onConnectionLost = newOnConnectionLost; + else + throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnConnectionLost, "onConnectionLost"])); + }; + + this._getOnMessageDelivered = function() { return client.onMessageDelivered; }; + this._setOnMessageDelivered = function(newOnMessageDelivered) { + if (typeof newOnMessageDelivered === "function") + client.onMessageDelivered = newOnMessageDelivered; + else + throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnMessageDelivered, "onMessageDelivered"])); + }; + + this._getOnMessageArrived = function() { return client.onMessageArrived; }; + this._setOnMessageArrived = function(newOnMessageArrived) { + if (typeof newOnMessageArrived === "function") + client.onMessageArrived = newOnMessageArrived; + else + throw new Error(format(ERROR.INVALID_TYPE, [typeof newOnMessageArrived, "onMessageArrived"])); + }; + + /** + * Connect this Messaging client to its server. + * + * @name Messaging.Client#connect + * @function + * @param {Object} [connectOptions] attributes used with the connection. + *

+ * Properties of the connect options are: + * @config {number} [timeout] If the connect has not succeeded within this number of seconds, it is deemed to have failed. + * The default is 30 seconds. + * @config {string} [userName] Authentication username for this connection. + * @config {string} [password] Authentication password for this connection. + * @config {Messaging.Message} [willMessage] sent by the server when the client disconnects abnormally. + * @config {Number} [keepAliveInterval] the server disconnects this client if there is no activity for this + * number of seconds. The default value of 60 seconds is assumed if not set. + * @config {boolean} [cleanSession] if true(default) the client and server persistent state is deleted on successful connect. + * @config {boolean} [useSSL] if present and true, use an SSL Websocket connection. + * @config {object} [invocationContext] passed to the onSuccess callback or onFailure callback. + * @config {function} [onSuccess] called when the connect acknowledgement has been received from the server. + * A single response object parameter is passed to the onSuccess callback containing the following fields: + *

    + *
  1. invocationContext as passed in to the onSuccess method in the connectOptions. + *
+ * @config {function} [onFailure] called when the connect request has failed or timed out. + * A single response object parameter is passed to the onFailure callback containing the following fields: + *
    + *
  1. invocationContext as passed in to the onFailure method in the connectOptions. + *
  2. errorCode a number indicating the nature of the error. + *
  3. errorMessage text describing the error. + *
+ * @config {Array} [hosts] If present this set of hostnames is tried in order in place + * of the host and port paramater on the construtor. The hosts and the matching ports are tried one at at time in order until + * one of then succeeds. + * @config {Array} [ports] If present this set of ports matching the hosts. + * @throws {InvalidState} if the client is not in disconnected state. The client must have received connectionLost + * or disconnected before calling connect for a second or subsequent time. + */ + this.connect = function (connectOptions) { + connectOptions = connectOptions || {} ; + validate(connectOptions, {timeout:"number", + userName:"string", + password:"string", + willMessage:"object", + keepAliveInterval:"number", + cleanSession:"boolean", + useSSL:"boolean", + invocationContext:"object", + onSuccess:"function", + onFailure:"function", + hosts:"object", + ports:"object"}); + + // If no keep alive interval is set, assume 60 seconds. + if (connectOptions.keepAliveInterval === undefined) + connectOptions.keepAliveInterval = 60; + + if (connectOptions.willMessage) { + if (!(connectOptions.willMessage instanceof Message)) + throw new Error(format(ERROR.INVALID_TYPE, [connectOptions.willMessage, "connectOptions.willMessage"])); + // The will message must have a payload that can be represented as a string. + // Cause the willMessage to throw an exception if this is not the case. + connectOptions.willMessage.stringPayload; + + if (typeof connectOptions.willMessage.destinationName === "undefined") + throw new Error(format(ERROR.INVALID_TYPE, [typeof connectOptions.willMessage.destinationName, "connectOptions.willMessage.destinationName"])); + } + if (typeof connectOptions.cleanSession === "undefined") + connectOptions.cleanSession = true; + if (connectOptions.hosts) { + if (!connectOptions.ports) + throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.ports, "connectOptions.ports"])); + if (!(connectOptions.hosts instanceof Array) ) + throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"])); + if (!(connectOptions.ports instanceof Array) ) + throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.ports, "connectOptions.ports"])); + if (connectOptions.hosts.length <1 ) + throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.hosts, "connectOptions.hosts"])); + if (connectOptions.hosts.length != connectOptions.ports.length) + throw new Error(format(ERROR.INVALID_ARGUMENT, [connectOptions.ports, "connectOptions.ports"])); + for (var i = 0; i + * @param {object} [subscribeOptions] used to control the subscription, as follows: + *

+ * @config {number} [qos] the maiximum qos of any publications sent as a result of making this subscription. + * @config {object} [invocationContext] passed to the onSuccess callback or onFailure callback. + * @config {function} [onSuccess] called when the subscribe acknowledgement has been received from the server. + * A single response object parameter is passed to the onSuccess callback containing the following fields: + *

    + *
  1. invocationContext if set in the subscribeOptions. + *
+ * @config {function} [onFailure] called when the subscribe request has failed or timed out. + * A single response object parameter is passed to the onFailure callback containing the following fields: + *
    + *
  1. invocationContext if set in the subscribeOptions. + *
  2. errorCode a number indicating the nature of the error. + *
  3. errorMessage text describing the error. + *
+ * @config {number} [timeout] which if present determines the number of seconds after which the onFailure calback is called + * the presence of a timeout does not prevent the onSuccess callback from being called when the MQTT Suback is eventually received. + * @throws {InvalidState} if the client is not in connected state. + */ + this.subscribe = function (filter, subscribeOptions) { + if (typeof filter !== "string") + throw new Error("Invalid argument:"+filter); + subscribeOptions = subscribeOptions || {} ; + validate(subscribeOptions, {qos:"number", + invocationContext:"object", + onSuccess:"function", + onFailure:"function", + timeout:"number" + }); + if (subscribeOptions.timeout && !subscribeOptions.onFailure) + throw new Error("subscribeOptions.timeout specified with no onFailure callback."); + if (typeof subscribeOptions.qos !== "undefined" + && !(subscribeOptions.qos === 0 || subscribeOptions.qos === 1 || subscribeOptions.qos === 2 )) + throw new Error(format(ERROR.INVALID_ARGUMENT, [subscribeOptions.qos, "subscribeOptions.qos"])); + client.subscribe(filter, subscribeOptions); + }; + + /** + * Unsubscribe for messages, stop receiving messages sent to destinations described by the filter. + * + * @name Messaging.Client#unsubscribe + * @function + * @param {string} filter describing the destinations to receive messages from. + * @param {object} [unsubscribeOptions] used to control the subscription, as follows: + *

+ * @config {object} [invocationContext] passed to the onSuccess callback or onFailure callback. + * @config {function} [onSuccess] called when the unsubscribe acknowledgement has been receive dfrom the server. + * A single response object parameter is passed to the onSuccess callback containing the following fields: + *

    + *
  1. invocationContext if set in the unsubscribeOptions. + *
+ * @config {function} [onFailure] called when the unsubscribe request has failed or timed out. + * A single response object parameter is passed to the onFailure callback containing the following fields: + *
    + *
  1. invocationContext if set in the unsubscribeOptions. + *
  2. errorCode a number indicating the nature of the error. + *
  3. errorMessage text describing the error. + *
+ * @config {number} [timeout] which if present determines the number of seconds after which the onFailure callback is called, the + * presence of a timeout does not prevent the onSuccess callback from being called when the MQTT UnSuback is eventually received. + * @throws {InvalidState} if the client is not in connected state. + */ + this.unsubscribe = function (filter, unsubscribeOptions) { + if (typeof filter !== "string") + throw new Error("Invalid argument:"+filter); + unsubscribeOptions = unsubscribeOptions || {} ; + validate(unsubscribeOptions, {invocationContext:"object", + onSuccess:"function", + onFailure:"function", + timeout:"number" + }); + if (unsubscribeOptions.timeout && !unsubscribeOptions.onFailure) + throw new Error("unsubscribeOptions.timeout specified with no onFailure callback."); + client.unsubscribe(filter, unsubscribeOptions); + }; + + /** + * Send a message to the consumers of the destination in the Message. + * + * @name Messaging.Client#send + * @function + * @param {Messaging.Message} message to send. + + * @throws {InvalidState} if the client is not in connected state. + */ + this.send = function (message) { + if (!(message instanceof Message)) + throw new Error("Invalid argument:"+typeof message); + if (typeof message.destinationName === "undefined") + throw new Error("Invalid parameter Message.destinationName:"+message.destinationName); + + client.send(message); + }; + + /** + * Normal disconnect of this Messaging client from its server. + * + * @name Messaging.Client#disconnect + * @function + * @throws {InvalidState} if the client is not in connected or connecting state. + */ + this.disconnect = function () { + client.disconnect(); + }; + + /** + * Get the contents of the trace log. + * + * @name Messaging.Client#getTraceLog + * @function + * @return {Object[]} tracebuffer containing the time ordered trace records. + */ + this.getTraceLog = function () { + return client.getTraceLog(); + } + + /** + * Start tracing. + * + * @name Messaging.Client#startTrace + * @function + */ + this.startTrace = function () { + client.startTrace(); + }; + + /** + * Stop tracing. + * + * @name Messaging.Client#stopTrace + * @function + */ + this.stopTrace = function () { + client.stopTrace(); + }; + }; + + Client.prototype = { + get host() { return this._getHost(); }, + set host(newHost) { this._setHost(newHost); }, + + get port() { return this._getPort(); }, + set port(newPort) { this._setPort(newPort); }, + + get clientId() { return this._getClientId(); }, + set clientId(newClientId) { this._setClientId(newClientId); }, + + get onConnectionLost() { return this._getOnConnectionLost(); }, + set onConnectionLost(newOnConnectionLost) { this._setOnConnectionLost(newOnConnectionLost); }, + + get onMessageDelivered() { return this._getOnMessageDelivered(); }, + set onMessageDelivered(newOnMessageDelivered) { this._setOnMessageDelivered(newOnMessageDelivered); }, + + get onMessageArrived() { return this._getOnMessageArrived(); }, + set onMessageArrived(newOnMessageArrived) { this._setOnMessageArrived(newOnMessageArrived); } + }; + + /** + * An application message, sent or received. + *

+ * Other programming languages, + * Java, + * C. + *

+ * All attributes may be null, which implies the default values. + * + * @name Messaging.Message + * @constructor + * @param {String|ArrayBuffer} payload The message data to be sent. + *

+ * @property {string} payloadString read only The payload as a string if the payload consists of valid UTF-8 characters. + * @property {ArrayBuffer} payloadBytes read only The payload as an ArrayBuffer. + *

+ * @property {string} destinationName mandatory The name of the destination to which the message is to be sent + * (for messages about to be sent) or the name of the destination from which the message has been received. + * (for messages received by the onMessage function). + *

+ * @property {number} qos The Quality of Service used to deliver the message. + *

+ *
0 Best effort (default). + *
1 At least once. + *
2 Exactly once. + *
+ *

+ * @property {Boolean} retained If true, the message is to be retained by the server and delivered + * to both current and future subscriptions. + * If false the server only delivers the message to current subscribers, this is the default for new Messages. + * A received message has the retained boolean set to true if the message was published + * with the retained boolean set to true + * and the subscrption was made after the message has been published. + *

+ * @property {Boolean} duplicate read only If true, this message might be a duplicate of one which has already been received. + * This is only set on messages received from the server. + * + */ + var Message = function (newPayload) { + var payload; + if ( typeof newPayload === "string" + || newPayload instanceof ArrayBuffer + || newPayload instanceof Int8Array + || newPayload instanceof Uint8Array + || newPayload instanceof Int16Array + || newPayload instanceof Uint16Array + || newPayload instanceof Int32Array + || newPayload instanceof Uint32Array + || newPayload instanceof Float32Array + || newPayload instanceof Float64Array + ) { + payload = newPayload; + } else { + throw (format(ERROR.INVALID_ARGUMENT, [newPayload, "newPayload"])); + } + + this._getPayloadString = function () { + if (typeof payload === "string") + return payload; + else + return parseUTF8(payload, 0, payload.length); + }; + + this._getPayloadBytes = function() { + if (typeof payload === "string") { + var buffer = new ArrayBuffer(UTF8Length(payload)); + var byteStream = new Uint8Array(buffer); + stringToUTF8(payload, byteStream, 0); + + return byteStream; + } else { + return payload; + }; + }; + + var destinationName = undefined; + this._getDestinationName = function() { return destinationName; }; + this._setDestinationName = function(newDestinationName) { + if (typeof newDestinationName === "string") + destinationName = newDestinationName; + else + throw new Error(format(ERROR.INVALID_ARGUMENT, [newDestinationName, "newDestinationName"])); + }; + + var qos = 0; + this._getQos = function() { return qos; }; + this._setQos = function(newQos) { + if (newQos === 0 || newQos === 1 || newQos === 2 ) + qos = newQos; + else + throw new Error("Invalid argument:"+newQos); + }; + + var retained = false; + this._getRetained = function() { return retained; }; + this._setRetained = function(newRetained) { + if (typeof newRetained === "boolean") + retained = newRetained; + else + throw new Error(format(ERROR.INVALID_ARGUMENT, [newRetained, "newRetained"])); + }; + + var duplicate = false; + this._getDuplicate = function() { return duplicate; }; + this._setDuplicate = function(newDuplicate) { duplicate = newDuplicate; }; + }; + + Message.prototype = { + get payloadString() { return this._getPayloadString(); }, + get payloadBytes() { return this._getPayloadBytes(); }, + + get destinationName() { return this._getDestinationName(); }, + set destinationName(newDestinationName) { this._setDestinationName(newDestinationName); }, + + get qos() { return this._getQos(); }, + set qos(newQos) { this._setQos(newQos); }, + + get retained() { return this._getRetained(); }, + set retained(newRetained) { this._setRetained(newRetained); }, + + get duplicate() { return this._getDuplicate(); }, + set duplicate(newDuplicate) { this._setDuplicate(newDuplicate); } + }; + + // Module contents. + return { + Client: Client, + Message: Message + }; +}; diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-connector.js b/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-connector.js new file mode 100644 index 0000000..7ab3d2c --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-connector.js @@ -0,0 +1,21 @@ +'uses strict'; +/** + * + * User: Martin Donnelly + * Date: 2016-03-11 + * Time: 10:22 + * + */ + +var pgp = require('pg-promise')(); + +var cn = { + host: 'localhost', + port: 5432, + database: 'mdot', + user: 'postgres', + password: '' +}; + +exports.dbConnection = pgp(cn); + diff --git a/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-save.js b/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-save.js new file mode 100644 index 0000000..64491e6 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/lib/server/db-save.js @@ -0,0 +1,128 @@ +'use strict'; + +var newId = require('uuid-pure').newId; +var atob = require('atob'); + +module.exports = function(db) { + var module = {}; + module.deviceIds = ['CENSIS-LoRa-1','CENSIS-LoRa-2','CENSIS-LoRa-3','CENSIS-LoRa-4','HIE-mobile-1','HIE-demo','HIE-mobile-2','HIE-smart-campus-1','HIE-smart-campus-2','HIE-smart-campus-3','HIE-smart-campus-4','HIE-smart-campus-5','HIE-smart-campus-6','HIE-smart-campus-7','HIE-mDot-1']; + + module.sqlInsertRawEvent = function(data) { + let _data = data; + + return new Promise(function(resolve, reject) { + db.func('insert_raw', + [_data.timestamp, _data.event]) + .then(()=> { + return resolve('ok'); + }) + .catch((err)=> { + return reject(err); + }); + }); + }; + + module.sqlInsertDecoded = function(data) { + let _data = data; + + console.log('sqlInsertDecoded', data); + return new Promise(function(resolve, reject) { + db.func('insert_decoded', + [_data.deviceid, _data.timestamp, _data.lux, _data.co2, _data.temp, _data.humidity, _data.sound]) + .then(()=> { + return resolve('ok'); + }) + .catch((err)=> { + return reject(err); + }); + }); + + }; + + module.addNewEvent = function(data) { + console.log('addNewEvent'); + var self = this; + return new Promise((resolve, reject) => { + + let _data = {}; + _data.timestamp = new Date(); + _data.event = data; + + self.sqlInsertRawEvent(_data) + .then((d)=> { + console.log('Postgres returns', d); + return resolve({reply: 'raw event inserted'}); + }) + .catch((err)=> { + return reject(err); + }); + }); + }; + + module.addProcessedEvent = function(data) { + console.log('addProcessedEvent'); + var self = this; + return new Promise((resolve, reject) => { + + let _data = self.rawBreaker(data); + + self.sqlInsertDecoded(_data) + .then((d)=> { + console.log('Postgres returns', d); + return resolve({reply: 'Processed event inserted'}); + }) + .catch((err)=> { + return reject(err); + }); + + + }); + + }; + + module.decoder = function(data) { + var _obj = {}; + var _data = atob(data).split(''); + + var bytes = _data.map(i => i.charCodeAt()); + + _obj.light = parseInt('0x' + ('0' + bytes[0]).substr(-2) + ('0' + bytes[1]).substr(-2)); + _obj.co2 = parseInt(_data[2] + _data[3] + _data[4] + _data[5] + _data[6], 10); + _obj.temp = (parseInt(_data[7] + _data[8] + _data[9] + _data[10] + _data[11], 10) - 1000) / 10; + _obj.humid = (parseInt(_data[12] + _data[13] + _data[14] + _data[15] + _data[16], 10) / 10); + _obj.noise = parseInt('0x' + ('0' + bytes[17]).substr(-2) + ('0' + bytes[18]).substr(-2)); + _obj.binData = bytes; + return _obj; + }; + + module.rawBreaker = function(data) { + var self = this; + var workObj = {}; + + var device_name = data.topic.split('/')[4]; + console.log('Device_name', device_name); + workObj.deviceid = self.deviceIds.indexOf(device_name); + + if (data.hasOwnProperty('data')) { + + var _data = self.decoder(data.data); + + workObj.lux = _data.light; + workObj.co2 = _data.co2; + workObj.temp = _data.temp; + workObj.humidity = _data.humid; + workObj.sound = _data.noise; + workObj.timestamp = new Date(); + + return workObj; + } else { + console.error('Data does not have base64 data'); + + return null; + } + + }; + + return module; +}; + diff --git a/mdot/mdot_mqtt/mdot_mqtt/maker.js b/mdot/mdot_mqtt/mdot_mqtt/maker.js new file mode 100644 index 0000000..3393f6a --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/maker.js @@ -0,0 +1,20 @@ +/** + * + * User: Martin Donnelly + * Date: 2016-06-28 + * Time: 14:50 + * + */ +var nano = require('nano')('http://localhost:5984'); + +var db_name = 'mqtt'; + +// Clean up the database we created previously +nano.db.destroy(db_name, function() { + // Create a new database + nano.db.create(db_name, function() { + // Specify the database we are going to use + var newDB = nano.use(db_name); + + }); + }); diff --git a/mdot/mdot_mqtt/mdot_mqtt/package.json b/mdot/mdot_mqtt/mdot_mqtt/package.json new file mode 100644 index 0000000..6c43dcb --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/package.json @@ -0,0 +1,75 @@ +{ + "name": "mdot_mqtt", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "atob": "^2.0.3", + "body-parser": "^1.15.1", + "cookie-parser": "*", + "ejs": "*", + "errorhandler": "*", + "express": "^4.13.4", + "express-session": "*", + "htmlparser": "^1.7.7", + "method-override": "*", + "minibus": "^3.1.0", + "morgan": "*", + "mqtt": "^1.10.0", + "mqtt_over_websockets": "0.0.1", + "node-localstorage": "^1.1.2", + "pg-promise": "^5.2.7", + "request": "^2.72.0", + "websocket": "^1.0.22" + }, + "devDependencies": { + "after": "^0.8.1", + "apn": "^1.7.8", + "apns": "^0.1.0", + "basic-authentication": "^1.6.2", + "chai": "^3.5.0", + "cheerio": "^0.20.0", + "clone": "^1.0.2", + "del": "^2.2.0", + "elapsed": "0.0.7", + "events": "^1.1.1", + "gulp": "^3.9.1", + "gulp-autoprefixer": "^3.1.0", + "gulp-cache": "^0.4.5", + "gulp-concat": "^2.6.0", + "gulp-cssmin": "^0.1.7", + "gulp-cssnano": "^2.1.2", + "gulp-debug": "^2.1.2", + "gulp-google-webfonts": "0.0.13", + "gulp-html-replace": "^1.5.5", + "gulp-htmlmin": "^2.0.0", + "gulp-inject": "^4.0.0", + "gulp-jshint": "^2.0.1", + "gulp-jsmin": "^0.1.5", + "gulp-livereload": "^3.8.1", + "gulp-notify": "^2.2.0", + "gulp-rename": "^1.2.2", + "gulp-size": "^2.1.0", + "gulp-strip-debug": "^1.1.0", + "gulp-uglify": "^2.0.0", + "jshint": "^2.9.2", + "jsonfile": "^2.3.1", + "log4js": "^0.6.36", + "mocha": "^3.0.2", + "mqtt-ws": "^0.2.0", + "nano": "^6.2.0", + "node-cron": "^1.1.1", + "require-dir": "^0.3.0", + "should": "^10.0.0", + "string": "^3.3.1", + "sugar": "^2.0.1", + "sugar-date": "^2.0.0", + "superagent": "^2.1.0", + "supertest": "^2.0.0" + }, + "author": "Martin Donnelly ", + "license": "ISC" +} diff --git a/mdot/mdot_mqtt/mdot_mqtt/process.json b/mdot/mdot_mqtt/mdot_mqtt/process.json new file mode 100644 index 0000000..0626314 --- /dev/null +++ b/mdot/mdot_mqtt/mdot_mqtt/process.json @@ -0,0 +1,20 @@ +{ + "apps": [ + { + "name": "SODashServer", + "script": "app.js", + "cwd": "/home/azureuser/live", + "watch": true, + "instances": 1, + "exec_mode": "cluster", + "combine_logs": true, + "max_memory_restart": "150M", + "restart_delay": 5000, + "ignore_watch": [ + "[\\/\\\\]\\./", + "node_modules", + "server/static" + ] + } + ] +} diff --git a/mdot/mdot_server/mdot_server/.editorconfig b/mdot/mdot_server/mdot_server/.editorconfig new file mode 100644 index 0000000..e86f5fa --- /dev/null +++ b/mdot/mdot_server/mdot_server/.editorconfig @@ -0,0 +1,32 @@ +; http://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.txt] +insert_final_newline = false +trim_trailing_whitespace = false + +[*.py] +indent_size = 4 + +[*.m] +indent_size = 4 + +[Makefile] +indent_style = tab +indent_size = 8 + +[*.{js,json}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/mdot/mdot_server/mdot_server/.gitignore b/mdot/mdot_server/mdot_server/.gitignore new file mode 100644 index 0000000..3b6a41e --- /dev/null +++ b/mdot/mdot_server/mdot_server/.gitignore @@ -0,0 +1,180 @@ +# Created by .ignore support plugin (hsz.mobi) +### Archives template +# It's better to unpack these files and commit the raw source because +# git has its own built in compression methods. +*.7z +*.jar +*.rar +*.zip +*.gz +*.bzip +*.bz2 +*.xz +*.lzma +*.cab + +#packing-only formats +*.iso +*.tar + +#package management formats +*.dmg +*.xpi +*.gem +*.egg +*.deb +*.rpm +*.msi +*.msm +*.msp +### Windows template +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### OSX template +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +### Node template +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules +bower_components + +### VisualStudioCode template +.settings + +### Xcode template +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata + +## Other +*.xccheckout +*.moved-aside +*.xcuserstate + +dist diff --git a/mdot/mdot_server/mdot_server/.jscsrc b/mdot/mdot_server/mdot_server/.jscsrc new file mode 100644 index 0000000..480fcc4 --- /dev/null +++ b/mdot/mdot_server/mdot_server/.jscsrc @@ -0,0 +1,46 @@ +{ + "disallowKeywords": ["with"], + "disallowKeywordsOnNewLine": ["else"], + "disallowMixedSpacesAndTabs": true, + "disallowMultipleVarDecl": "exceptUndefined", + "disallowNewlineBeforeBlockStatements": true, + "disallowQuotedKeysInObjects": true, + "disallowSpaceAfterObjectKeys": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "disallowSpacesInFunction": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInsideParentheses": true, + "disallowTrailingWhitespace": true, + "maximumLineLength": 160, + "requireCamelCaseOrUpperCaseIdentifiers": false, + "requireCapitalizedComments": true, + "requireCapitalizedConstructors": true, + "requireCurlyBraces": true, + "requireSpaceAfterKeywords": [ + "if", + "else", + "for", + "while", + "do", + "switch", + "case", + "return", + "try", + "catch", + "typeof" + ], + "requireSpaceAfterLineComment": true, + "requireSpaceAfterBinaryOperators": true, + "requireSpaceBeforeBinaryOperators": true, + "requireSpaceBeforeBlockStatements": true, + "requireSpaceBeforeObjectValues": true, + "requireSpacesInFunction": { + "beforeOpeningCurlyBrace": true + }, + "requireTrailingComma": false, + "requireEarlyReturn": false, + "validateIndentation": 2, + "validateLineBreaks": "LF", + "validateQuoteMarks": "'" +} diff --git a/mdot/mdot_server/mdot_server/.jshintrc b/mdot/mdot_server/mdot_server/.jshintrc new file mode 100644 index 0000000..375085b --- /dev/null +++ b/mdot/mdot_server/mdot_server/.jshintrc @@ -0,0 +1,37 @@ +{ + "predef": [ + "Promise", + "$" + ], + "globals": { + "$": false, + "MicroEvent": false + }, + "node":true, + "browser": true, + "boss": true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true, + "unused": true, + "supernew":true +} diff --git a/mdot/mdot_server/mdot_server/app.js b/mdot/mdot_server/mdot_server/app.js new file mode 100644 index 0000000..937bbf9 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app.js @@ -0,0 +1,88 @@ +/** + * Created by Martin on 08/02/2016. + */ +'use strict'; +var express = require('express'); +var path = require('path'); +var http = require('http'); +var ejs = require('ejs'); +var morgan = require('morgan'); +var cookieparser = require('cookie-parser'); +var session = require('express-session'); +var methodoverride = require('method-override'); +var bodyparser = require('body-parser'); +var errorhandler = require('errorhandler'); +var log4js = require('log4js'); +var logger = log4js.getLogger(); + + +var WebSocketServer = require('websocket').server; + +var EventEmitter = require('events'); +var busEmitter = new EventEmitter(); + +var apn = require('apn'); + +require('sugar-date'); + +var isProduction = false; + + +var mdotApi = require('./lib/mdot/api.js'); + + +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +if (process.env.NODE_ENV === 'production') { + isProduction = true; +} + +logger.warn('isProduction:', isProduction); + +var app = express(); + +app.set('port', process.env.PORT || 4545); +app.set('views', __dirname + '/views'); +app.set('view engine', 'ejs'); +app.use(morgan('combined')); +app.use(cookieparser('your secret here')); +app.use(session({ + secret: '1234567890QWERTY', resave: false, saveUninitialized: false +})); +/* 'default', 'short', 'tiny', 'dev' */ +app.use(methodoverride()); + +app.use(bodyparser.urlencoded({extended: false})); + +// Parse application/json +app.use(bodyparser.json()); + +app.use(function(req, res, next) { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Headers', 'X-Requested-With'); + next(); +}); + +// Run npm start --production to use dist +var staticDir = isProduction ? 'dist' : 'app'; + +app.use(express.static(path.join(__dirname, staticDir))); +app.use(errorhandler({dumpExceptions: true, showStack: true})); + + +// Events and sockets + +function originIsAllowed(origin) { + // Put logic here to detect whether the specified origin is allowed. + return true; +} + +// glue routes +mdotApi(app); + +//app.get('/api/mdot/:id', mDot.getData); + +app.listen(3010, function() { + logger.info('Express listening on 3010'); + +}); diff --git a/mdot/mdot_server/mdot_server/app/css/app.css b/mdot/mdot_server/mdot_server/app/css/app.css new file mode 100644 index 0000000..f92cb29 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/app.css @@ -0,0 +1,276 @@ +body { + font-family: Ubuntu, "Helvetica Neue", Helvetica, arial, sans-serif; + background-color: #004c6d; + } + +html, body { + height: 100%; + overflow: hidden; +} + + + +#weatherIcon { + margin-left:25%; + margin-right:25%; + height:70px; + width:70px; + + } + +#lightR, #projR { color: red !important; } + +#lightG, #projG { color: green !important; } + +#lightB, #projB { color: blue !important; } + +#lightW, #projW { background-color: #aabbcc; } + +.lightBG, .heatingBG, .projectorBG { + float: right; + } + +/*.lightBG { + background-color: rgba(255, 255, 0, 0.3); + } + +.heatingBG { + background-color: rgba(255, 0, 255, 0.3); + } + +.projectorBG { + background-color: rgba(0, 255, 255, 0.3); + }*/ + +.mui-panel { + background-color: #015579; + } + +.h105 { + height: 100px; + } + +.mdHeading { + overflow: hidden; + } + +.mui--text-title { + color: #ffffff; + } + +.item_content { + height: 100px; + /* border: 1px solid grey;*/ + min-height: 100px; + overflow: hidden; + } + +.item_content a.title { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #ffffff; + } + +.item_content div.body, .item_content div.site, .item_content div.tags { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #313131; + } + +.time, .date, .temp { + font-family: 'Ubuntu Condensed', sans-serif; + font-size: 80px; + color: #bad649; + } + +.time span.hour:after { + content: ":"; + } + +.date { + font-size: 35px; + line-height: 1; + } + +.temp::after { + content: "°c"; + } + +.item_content div.tags { + color: blue; + } + +.noConnection { + color: rgb(244, 150, 26); + } + +#caltext { + color: #fff; + } + +/* Smartphones (portrait and landscape) ----------- */ +@media only screen and (min-device-width: 320px) and (max-device-width: 480px) { + /* Styles */ + .time, .date, .temp { + font-family: 'Ubuntu Condensed', sans-serif; + font-size: 33px; + /*color: #ff0000;*/ + } + + .time { + font-size: 50px; + line-height: 1; + } + + .time span.hour:after { + content: "\a"; + white-space: pre; + } + + .temp { + font-size: 70px; + } + + .temp::after { + content: "°"; + } + + .wd-we { + font-size: 75%; + } + + .mo { + font-size: 85%; + } + + .mo.mo-1, .mo.mo-10 { + font-size: 70%; + } + + .mo.mo-2 { + font-size: 65%; + } + + .mo.mo-8 { + font-size: 80%; + } + + .mo.mo-9 { + font-size: 55%; + } + + .mo.mo-11, .mo.mo-12 { + font-size: 60%; + } + + } + +/* Smartphones (landscape) ----------- */ +@media only screen and (min-width: 321px) { + /* Styles */ + } + +/* Smartphones (portrait) ----------- */ +@media only screen and (max-width: 320px) { + /* Styles */ + } + +.spinner { + margin: 25px auto 0; + width: 70px; + text-align: center; + } + +.spinner > div { + width: 18px; + height: 18px; + background-color: rgb(244, 150, 26); + border-radius: 100%; + display: inline-block; + -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: sk-bouncedelay 1.4s infinite ease-in-out both; + } + +.spinner .bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + } + +.spinner .bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; + } + +@-webkit-keyframes sk-bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0) } + 40% { -webkit-transform: scale(1.0) } + } + +@keyframes sk-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0); + transform: scale(0); + } + 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } + } + +.material-icons { + color: #e5f7fd; + } + +.material-icons.md-18 { font-size: 18px; } + +.material-icons.md-24 { font-size: 24px; } + +.material-icons.md-36 { font-size: 36px; } + +.material-icons.md-48 { font-size: 48px; } + +.material-icons.md-100 { font-size: 100px; } + +/* Rules for using icons as black on a light background. */ +.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); } + +.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); } + +/* Rules for using icons as white on a dark background. */ +.material-icons.md-light { color: rgba(255, 255, 255, 1); } + +.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); } + +.material-icons.md-bulb { + content: "" + } + +/* +fan : toys + + + + +bulb : lightbulb_outline + + +calendar: event_note + + +projector: cast + + +*/ + +.md-display { + opacity: 1; + transition: opacity 0.3s, visibility 0.3s; + + } + +.lostConnection { + opacity: 0.5; + transition: opacity 0.3s, visibility 0.3s; +} diff --git a/mdot/mdot_server/mdot_server/app/css/material-icons.css b/mdot/mdot_server/mdot_server/app/css/material-icons.css new file mode 100644 index 0000000..986e9d3 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/material-icons.css @@ -0,0 +1,15 @@ +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; +} diff --git a/mdot/mdot_server/mdot_server/app/css/mui.css b/mdot/mdot_server/mdot_server/app/css/mui.css new file mode 100644 index 0000000..cfe1de1 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/mui.css @@ -0,0 +1,1912 @@ +/** + * MUI Colors module + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ +html { + font-family: sans-serif; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/** + * Remove default margin. + */ +body { + margin: 0; } + +/* HTML5 display definitions + ========================================================================== */ +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; } + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ +audio, +canvas, +progress, +video { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ } + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +audio:not([controls]) { + display: none; + height: 0; } + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ +[hidden], +template { + display: none; } + +/* Links + ========================================================================== */ +/** + * Remove the gray background color from active links in IE 10. + */ +a { + background-color: transparent; } + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ +a:active, +a:hover { + outline: 0; } + +/* Text-level semantics + ========================================================================== */ +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ +abbr[title] { + border-bottom: 1px dotted; } + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ +b, +strong { + font-weight: bold; } + +/** + * Address styling not present in Safari and Chrome. + */ +dfn { + font-style: italic; } + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/** + * Address styling not present in IE 8/9. + */ +mark { + background: #ff0; + color: #000; } + +/** + * Address inconsistent and variable font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +/* Embedded content + ========================================================================== */ +/** + * Remove border when inside `a` element in IE 8/9/10. + */ +img { + border: 0; } + +/** + * Correct overflow not hidden in IE 9/10/11. + */ +svg:not(:root) { + overflow: hidden; } + +/* Grouping content + ========================================================================== */ +/** + * Address margin not present in IE 8/9 and Safari. + */ +figure { + margin: 1em 40px; } + +/** + * Address differences between Firefox and other browsers. + */ +hr { + box-sizing: content-box; + height: 0; } + +/** + * Contain overflow in all browsers. + */ +pre { + overflow: auto; } + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; } + +/* Forms + ========================================================================== */ +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ +button, +input, +optgroup, +select, +textarea { + color: inherit; + /* 1 */ + font: inherit; + /* 2 */ + margin: 0; + /* 3 */ } + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ +button { + overflow: visible; } + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ +button, +select { + text-transform: none; } + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ } + +/** + * Re-set default cursor for disabled elements. + */ +button[disabled], +html input[disabled] { + cursor: default; } + +/** + * Remove inner padding and border in Firefox 4+. + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; } + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ +input { + line-height: normal; } + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + box-sizing: content-box; + /* 2 */ } + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * Define consistent border, margin, and padding. + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; } + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ +textarea { + overflow: auto; } + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ +optgroup { + font-weight: bold; } + +/* Tables + ========================================================================== */ +/** + * Remove most spacing between table cells. + */ +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; } + +/** + * MUI Colors module + */ +/** + * MUI Reboot + */ +* { + box-sizing: border-box; } + +*:before, +*:after { + box-sizing: border-box; } + +html { + font-size: 10px; + -webkit-tap-highlight-color: transparent; } + +body { + font-family: Arial, Verdana, Tahoma; + font-size: 14px; + font-weight: 400; + line-height: 1.429; + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; } + +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; } + +a { + color: #2196F3; + text-decoration: none; } + a:hover, a:focus { + color: #1976D2; + text-decoration: underline; } + a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; } + +p { + margin: 0 0 10px; } + +ul, +ol { + margin-top: 0; + margin-bottom: 10px; } + +figure { + margin: 0; } + +img { + vertical-align: middle; } + +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + height: 1px; + background-color: rgba(0, 0, 0, 0.12); } + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 10px; + font-size: 21px; + color: rgba(0, 0, 0, 0.87); + line-height: inherit; + border: 0; } + +input[type="search"] { + box-sizing: border-box; + -webkit-appearance: none; } + +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; } + +input[type="radio"]:disabled, +input[type="checkbox"]:disabled { + cursor: not-allowed; } + +strong { + font-weight: 700; } + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #2196F3; } + +h1, h2, h3 { + margin-top: 20px; + margin-bottom: 10px; } + +h4, h5, h6 { + margin-top: 10px; + margin-bottom: 10px; } + +/** + * MUI Appbar + */ +.mui--appbar-height { + height: 56px; } + +.mui--appbar-min-height, .mui-appbar { + min-height: 56px; } + +.mui--appbar-line-height { + line-height: 56px; } + +.mui--appbar-top { + top: 56px; } + +@media (orientation: landscape) and (max-height: 480px) { + .mui--appbar-height { + height: 48px; } + .mui--appbar-min-height, .mui-appbar { + min-height: 48px; } + .mui--appbar-line-height { + line-height: 48px; } + .mui--appbar-top { + top: 48px; } } + +@media (min-width: 480px) { + .mui--appbar-height { + height: 64px; } + .mui--appbar-min-height, .mui-appbar { + min-height: 64px; } + .mui--appbar-line-height { + line-height: 64px; } + .mui--appbar-top { + top: 64px; } } + +.mui-appbar { + background-color: #2196F3; + color: #FFF; } + +/** + * MUI Buttons + */ +.mui-btn { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + font-weight: 500; + font-size: 14px; + line-height: 18px; + text-transform: uppercase; + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; + transition: all 0.2s ease-in-out; + display: inline-block; + height: 36px; + padding: 0 26px; + margin-top: 6px; + margin-bottom: 6px; + border: none; + border-radius: 2px; + cursor: pointer; + touch-action: manipulation; + background-image: none; + text-align: center; + line-height: 36px; + vertical-align: middle; + white-space: nowrap; + user-select: none; + font-size: 14px; + letter-spacing: 0.03em; + position: relative; + overflow: hidden; } + .mui-btn:hover, .mui-btn:focus, .mui-btn:active { + color: rgba(0, 0, 0, 0.87); + background-color: white; } + .mui-btn[disabled]:hover, .mui-btn[disabled]:focus, .mui-btn[disabled]:active { + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; } + .mui-btn.mui-btn--flat { + color: rgba(0, 0, 0, 0.87); + background-color: transparent; } + .mui-btn.mui-btn--flat:hover, .mui-btn.mui-btn--flat:focus, .mui-btn.mui-btn--flat:active { + color: rgba(0, 0, 0, 0.87); + background-color: #f2f2f2; } + .mui-btn.mui-btn--flat[disabled]:hover, .mui-btn.mui-btn--flat[disabled]:focus, .mui-btn.mui-btn--flat[disabled]:active { + color: rgba(0, 0, 0, 0.87); + background-color: transparent; } + .mui-btn:hover, .mui-btn:focus, .mui-btn:active { + outline: 0; + text-decoration: none; + color: rgba(0, 0, 0, 0.87); } + .mui-btn:hover, .mui-btn:focus { + box-shadow: 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn:hover, .mui-btn:focus { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } } + .mui-btn:active { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn:active { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } } + .mui-btn:disabled, .mui-btn.mui--is-disabled { + cursor: not-allowed; + pointer-events: none; + opacity: 0.60; + box-shadow: none; } + +.mui-btn + .mui-btn { + margin-left: 8px; } + +.mui-btn--flat { + background-color: transparent; } + .mui-btn--flat:hover, .mui-btn--flat:focus, .mui-btn--flat:active { + box-shadow: none; + background-color: #f2f2f2; } + +.mui-btn--raised, .mui-btn--fab { + box-shadow: 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn--raised, .mui-btn--fab { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } } + .mui-btn--raised:active, .mui-btn--fab:active { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn--raised:active, .mui-btn--fab:active { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } } + +.mui-btn--fab { + position: relative; + padding: 0; + width: 55px; + height: 55px; + line-height: 55px; + border-radius: 50%; + z-index: 1; } + +.mui-btn--primary { + color: #FFF; + background-color: #2196F3; } + .mui-btn--primary:hover, .mui-btn--primary:focus, .mui-btn--primary:active { + color: #FFF; + background-color: #39a1f4; } + .mui-btn--primary[disabled]:hover, .mui-btn--primary[disabled]:focus, .mui-btn--primary[disabled]:active { + color: #FFF; + background-color: #2196F3; } + .mui-btn--primary.mui-btn--flat { + color: #2196F3; + background-color: transparent; } + .mui-btn--primary.mui-btn--flat:hover, .mui-btn--primary.mui-btn--flat:focus, .mui-btn--primary.mui-btn--flat:active { + color: #2196F3; + background-color: #f2f2f2; } + .mui-btn--primary.mui-btn--flat[disabled]:hover, .mui-btn--primary.mui-btn--flat[disabled]:focus, .mui-btn--primary.mui-btn--flat[disabled]:active { + color: #2196F3; + background-color: transparent; } + +.mui-btn--dark { + color: #FFF; + background-color: #424242; } + .mui-btn--dark:hover, .mui-btn--dark:focus, .mui-btn--dark:active { + color: #FFF; + background-color: #4f4f4f; } + .mui-btn--dark[disabled]:hover, .mui-btn--dark[disabled]:focus, .mui-btn--dark[disabled]:active { + color: #FFF; + background-color: #424242; } + .mui-btn--dark.mui-btn--flat { + color: #424242; + background-color: transparent; } + .mui-btn--dark.mui-btn--flat:hover, .mui-btn--dark.mui-btn--flat:focus, .mui-btn--dark.mui-btn--flat:active { + color: #424242; + background-color: #f2f2f2; } + .mui-btn--dark.mui-btn--flat[disabled]:hover, .mui-btn--dark.mui-btn--flat[disabled]:focus, .mui-btn--dark.mui-btn--flat[disabled]:active { + color: #424242; + background-color: transparent; } + +.mui-btn--danger { + color: #FFF; + background-color: #F44336; } + .mui-btn--danger:hover, .mui-btn--danger:focus, .mui-btn--danger:active { + color: #FFF; + background-color: #f55a4e; } + .mui-btn--danger[disabled]:hover, .mui-btn--danger[disabled]:focus, .mui-btn--danger[disabled]:active { + color: #FFF; + background-color: #F44336; } + .mui-btn--danger.mui-btn--flat { + color: #F44336; + background-color: transparent; } + .mui-btn--danger.mui-btn--flat:hover, .mui-btn--danger.mui-btn--flat:focus, .mui-btn--danger.mui-btn--flat:active { + color: #F44336; + background-color: #f2f2f2; } + .mui-btn--danger.mui-btn--flat[disabled]:hover, .mui-btn--danger.mui-btn--flat[disabled]:focus, .mui-btn--danger.mui-btn--flat[disabled]:active { + color: #F44336; + background-color: transparent; } + +.mui-btn--accent { + color: #004c6d; + background-color: #bad649; } + .mui-btn--accent:hover, .mui-btn--accent:focus, .mui-btn--accent:active { + color: #004c6d; + background-color: #c2db5e; } + .mui-btn--accent[disabled]:hover, .mui-btn--accent[disabled]:focus, .mui-btn--accent[disabled]:active { + color: #004c6d; + background-color: #bad649; } + .mui-btn--accent.mui-btn--flat { + color: #bad649; + background-color: transparent; } + .mui-btn--accent.mui-btn--flat:hover, .mui-btn--accent.mui-btn--flat:focus, .mui-btn--accent.mui-btn--flat:active { + color: #bad649; + background-color: #f2f2f2; } + .mui-btn--accent.mui-btn--flat[disabled]:hover, .mui-btn--accent.mui-btn--flat[disabled]:focus, .mui-btn--accent.mui-btn--flat[disabled]:active { + color: #bad649; + background-color: transparent; } + +.mui-btn--small { + height: 30.6px; + line-height: 30.6px; + padding: 0 16px; + font-size: 13px; } + +.mui-btn--large { + height: 54px; + line-height: 54px; + padding: 0 26px; + font-size: 14px; } + +.mui-btn--fab.mui-btn--small { + width: 44px; + height: 44px; + line-height: 44px; } + +.mui-btn--fab.mui-btn--large { + width: 75px; + height: 75px; + line-height: 75px; } + +/** + * MUI Checkboxe and Radio Components + */ +.mui-radio, +.mui-checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; } + .mui-radio > label, + .mui-checkbox > label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; } + +.mui-radio > label > input[type="radio"], +.mui-radio--inline > label > input[type="radio"], +.mui-checkbox > label > input[type="checkbox"], +.mui-checkbox--inline > label > input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px; } + +.mui-radio + .mui-radio, +.mui-checkbox + .mui-checkbox { + margin-top: -5px; } + +.mui-radio--inline, +.mui-checkbox--inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; } + .mui-radio--inline > input[type="radio"], + .mui-radio--inline > input[type="checkbox"], + .mui-radio--inline > label > input[type="radio"], + .mui-radio--inline > label > input[type="checkbox"], + .mui-checkbox--inline > input[type="radio"], + .mui-checkbox--inline > input[type="checkbox"], + .mui-checkbox--inline > label > input[type="radio"], + .mui-checkbox--inline > label > input[type="checkbox"] { + margin: 4px 0 0; + line-height: normal; } + +.mui-radio--inline + .mui-radio--inline, +.mui-checkbox--inline + .mui-checkbox--inline { + margin-top: 0; + margin-left: 10px; } + +/** + * MUI Container module + */ +.mui-container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; } + .mui-container:before, .mui-container:after { + content: " "; + display: table; } + .mui-container:after { + clear: both; } + @media (min-width: 544px) { + .mui-container { + max-width: 570px; } } + @media (min-width: 768px) { + .mui-container { + max-width: 740px; } } + @media (min-width: 992px) { + .mui-container { + max-width: 960px; } } + @media (min-width: 1200px) { + .mui-container { + max-width: 1170px; } } + +.mui-container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; } + .mui-container-fluid:before, .mui-container-fluid:after { + content: " "; + display: table; } + .mui-container-fluid:after { + clear: both; } + +/** + * MUI Divider Component and CSS Helpers + */ +.mui-divider { + display: block; + height: 1px; + background-color: rgba(0, 0, 0, 0.12); } + +.mui--divider-top { + border-top: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-bottom { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-left { + border-left: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-right { + border-right: 1px solid rgba(0, 0, 0, 0.12); } + +/** + * MUI Dropdown module + */ +.mui-dropdown { + display: inline-block; + position: relative; } + +[data-mui-toggle="dropdown"] { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + outline: 0; } + +.mui-dropdown__menu { + position: absolute; + top: 100%; + left: 0; + display: none; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + text-align: left; + background-color: #FFF; + border-radius: 2px; + z-index: 1; + background-clip: padding-box; } + .mui-dropdown__menu.mui--is-open { + display: block; } + .mui-dropdown__menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.429; + color: rgba(0, 0, 0, 0.87); + white-space: nowrap; } + .mui-dropdown__menu > li > a:hover, .mui-dropdown__menu > li > a:focus { + text-decoration: none; + color: rgba(0, 0, 0, 0.87); + background-color: #EEEEEE; } + .mui-dropdown__menu > .mui--is-disabled > a, .mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus { + color: #EEEEEE; } + .mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + cursor: not-allowed; } + +.mui-dropdown__menu--right { + left: auto; + right: 0; } + +/** + * MUI Form Component + */ +@media (min-width: 544px) { + .mui-form--inline > .mui-textfield { + display: inline-block; + margin-bottom: 0; } + .mui-form--inline > .mui-radio, + .mui-form--inline > .mui-checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; } + .mui-form--inline > .mui-radio > label, + .mui-form--inline > .mui-checkbox > label { + padding-left: 0; } + .mui-form--inline > .mui-radio > label > input[type="radio"], + .mui-form--inline > .mui-checkbox > label > input[type="checkbox"] { + position: relative; + margin-left: 0; } + .mui-form--inline > .mui-select { + display: inline-block; } + .mui-form--inline > .mui-btn { + margin-bottom: 0; + margin-top: 0; + vertical-align: bottom; } } + +/** + * MUI Grid module + */ +.mui-row { + margin-left: -15px; + margin-right: -15px; } + .mui-row:before, .mui-row:after { + content: " "; + display: table; } + .mui-row:after { + clear: both; } + +.mui-col-xs-1, .mui-col-sm-1, .mui-col-md-1, .mui-col-lg-1, .mui-col-xs-2, .mui-col-sm-2, .mui-col-md-2, .mui-col-lg-2, .mui-col-xs-3, .mui-col-sm-3, .mui-col-md-3, .mui-col-lg-3, .mui-col-xs-4, .mui-col-sm-4, .mui-col-md-4, .mui-col-lg-4, .mui-col-xs-5, .mui-col-sm-5, .mui-col-md-5, .mui-col-lg-5, .mui-col-xs-6, .mui-col-sm-6, .mui-col-md-6, .mui-col-lg-6, .mui-col-xs-7, .mui-col-sm-7, .mui-col-md-7, .mui-col-lg-7, .mui-col-xs-8, .mui-col-sm-8, .mui-col-md-8, .mui-col-lg-8, .mui-col-xs-9, .mui-col-sm-9, .mui-col-md-9, .mui-col-lg-9, .mui-col-xs-10, .mui-col-sm-10, .mui-col-md-10, .mui-col-lg-10, .mui-col-xs-11, .mui-col-sm-11, .mui-col-md-11, .mui-col-lg-11, .mui-col-xs-12, .mui-col-sm-12, .mui-col-md-12, .mui-col-lg-12 { + min-height: 1px; + padding-left: 15px; + padding-right: 15px; } + +.mui-col-xs-1, .mui-col-xs-2, .mui-col-xs-3, .mui-col-xs-4, .mui-col-xs-5, .mui-col-xs-6, .mui-col-xs-7, .mui-col-xs-8, .mui-col-xs-9, .mui-col-xs-10, .mui-col-xs-11, .mui-col-xs-12 { + float: left; } + +.mui-col-xs-1 { + width: 8.33333%; } + +.mui-col-xs-2 { + width: 16.66667%; } + +.mui-col-xs-3 { + width: 25%; } + +.mui-col-xs-4 { + width: 33.33333%; } + +.mui-col-xs-5 { + width: 41.66667%; } + +.mui-col-xs-6 { + width: 50%; } + +.mui-col-xs-7 { + width: 58.33333%; } + +.mui-col-xs-8 { + width: 66.66667%; } + +.mui-col-xs-9 { + width: 75%; } + +.mui-col-xs-10 { + width: 83.33333%; } + +.mui-col-xs-11 { + width: 91.66667%; } + +.mui-col-xs-12 { + width: 100%; } + +.mui-col-xs-offset-0 { + margin-left: 0%; } + +.mui-col-xs-offset-1 { + margin-left: 8.33333%; } + +.mui-col-xs-offset-2 { + margin-left: 16.66667%; } + +.mui-col-xs-offset-3 { + margin-left: 25%; } + +.mui-col-xs-offset-4 { + margin-left: 33.33333%; } + +.mui-col-xs-offset-5 { + margin-left: 41.66667%; } + +.mui-col-xs-offset-6 { + margin-left: 50%; } + +.mui-col-xs-offset-7 { + margin-left: 58.33333%; } + +.mui-col-xs-offset-8 { + margin-left: 66.66667%; } + +.mui-col-xs-offset-9 { + margin-left: 75%; } + +.mui-col-xs-offset-10 { + margin-left: 83.33333%; } + +.mui-col-xs-offset-11 { + margin-left: 91.66667%; } + +.mui-col-xs-offset-12 { + margin-left: 100%; } + +@media (min-width: 544px) { + .mui-col-sm-1, .mui-col-sm-2, .mui-col-sm-3, .mui-col-sm-4, .mui-col-sm-5, .mui-col-sm-6, .mui-col-sm-7, .mui-col-sm-8, .mui-col-sm-9, .mui-col-sm-10, .mui-col-sm-11, .mui-col-sm-12 { + float: left; } + .mui-col-sm-1 { + width: 8.33333%; } + .mui-col-sm-2 { + width: 16.66667%; } + .mui-col-sm-3 { + width: 25%; } + .mui-col-sm-4 { + width: 33.33333%; } + .mui-col-sm-5 { + width: 41.66667%; } + .mui-col-sm-6 { + width: 50%; } + .mui-col-sm-7 { + width: 58.33333%; } + .mui-col-sm-8 { + width: 66.66667%; } + .mui-col-sm-9 { + width: 75%; } + .mui-col-sm-10 { + width: 83.33333%; } + .mui-col-sm-11 { + width: 91.66667%; } + .mui-col-sm-12 { + width: 100%; } + .mui-col-sm-offset-0 { + margin-left: 0%; } + .mui-col-sm-offset-1 { + margin-left: 8.33333%; } + .mui-col-sm-offset-2 { + margin-left: 16.66667%; } + .mui-col-sm-offset-3 { + margin-left: 25%; } + .mui-col-sm-offset-4 { + margin-left: 33.33333%; } + .mui-col-sm-offset-5 { + margin-left: 41.66667%; } + .mui-col-sm-offset-6 { + margin-left: 50%; } + .mui-col-sm-offset-7 { + margin-left: 58.33333%; } + .mui-col-sm-offset-8 { + margin-left: 66.66667%; } + .mui-col-sm-offset-9 { + margin-left: 75%; } + .mui-col-sm-offset-10 { + margin-left: 83.33333%; } + .mui-col-sm-offset-11 { + margin-left: 91.66667%; } + .mui-col-sm-offset-12 { + margin-left: 100%; } } + +@media (min-width: 768px) { + .mui-col-md-1, .mui-col-md-2, .mui-col-md-3, .mui-col-md-4, .mui-col-md-5, .mui-col-md-6, .mui-col-md-7, .mui-col-md-8, .mui-col-md-9, .mui-col-md-10, .mui-col-md-11, .mui-col-md-12 { + float: left; } + .mui-col-md-1 { + width: 8.33333%; } + .mui-col-md-2 { + width: 16.66667%; } + .mui-col-md-3 { + width: 25%; } + .mui-col-md-4 { + width: 33.33333%; } + .mui-col-md-5 { + width: 41.66667%; } + .mui-col-md-6 { + width: 50%; } + .mui-col-md-7 { + width: 58.33333%; } + .mui-col-md-8 { + width: 66.66667%; } + .mui-col-md-9 { + width: 75%; } + .mui-col-md-10 { + width: 83.33333%; } + .mui-col-md-11 { + width: 91.66667%; } + .mui-col-md-12 { + width: 100%; } + .mui-col-md-offset-0 { + margin-left: 0%; } + .mui-col-md-offset-1 { + margin-left: 8.33333%; } + .mui-col-md-offset-2 { + margin-left: 16.66667%; } + .mui-col-md-offset-3 { + margin-left: 25%; } + .mui-col-md-offset-4 { + margin-left: 33.33333%; } + .mui-col-md-offset-5 { + margin-left: 41.66667%; } + .mui-col-md-offset-6 { + margin-left: 50%; } + .mui-col-md-offset-7 { + margin-left: 58.33333%; } + .mui-col-md-offset-8 { + margin-left: 66.66667%; } + .mui-col-md-offset-9 { + margin-left: 75%; } + .mui-col-md-offset-10 { + margin-left: 83.33333%; } + .mui-col-md-offset-11 { + margin-left: 91.66667%; } + .mui-col-md-offset-12 { + margin-left: 100%; } } + +@media (min-width: 992px) { + .mui-col-lg-1, .mui-col-lg-2, .mui-col-lg-3, .mui-col-lg-4, .mui-col-lg-5, .mui-col-lg-6, .mui-col-lg-7, .mui-col-lg-8, .mui-col-lg-9, .mui-col-lg-10, .mui-col-lg-11, .mui-col-lg-12 { + float: left; } + .mui-col-lg-1 { + width: 8.33333%; } + .mui-col-lg-2 { + width: 16.66667%; } + .mui-col-lg-3 { + width: 25%; } + .mui-col-lg-4 { + width: 33.33333%; } + .mui-col-lg-5 { + width: 41.66667%; } + .mui-col-lg-6 { + width: 50%; } + .mui-col-lg-7 { + width: 58.33333%; } + .mui-col-lg-8 { + width: 66.66667%; } + .mui-col-lg-9 { + width: 75%; } + .mui-col-lg-10 { + width: 83.33333%; } + .mui-col-lg-11 { + width: 91.66667%; } + .mui-col-lg-12 { + width: 100%; } + .mui-col-lg-offset-0 { + margin-left: 0%; } + .mui-col-lg-offset-1 { + margin-left: 8.33333%; } + .mui-col-lg-offset-2 { + margin-left: 16.66667%; } + .mui-col-lg-offset-3 { + margin-left: 25%; } + .mui-col-lg-offset-4 { + margin-left: 33.33333%; } + .mui-col-lg-offset-5 { + margin-left: 41.66667%; } + .mui-col-lg-offset-6 { + margin-left: 50%; } + .mui-col-lg-offset-7 { + margin-left: 58.33333%; } + .mui-col-lg-offset-8 { + margin-left: 66.66667%; } + .mui-col-lg-offset-9 { + margin-left: 75%; } + .mui-col-lg-offset-10 { + margin-left: 83.33333%; } + .mui-col-lg-offset-11 { + margin-left: 91.66667%; } + .mui-col-lg-offset-12 { + margin-left: 100%; } } + +@media (min-width: 1200px) { + .mui-col-xl-1, .mui-col-xl-2, .mui-col-xl-3, .mui-col-xl-4, .mui-col-xl-5, .mui-col-xl-6, .mui-col-xl-7, .mui-col-xl-8, .mui-col-xl-9, .mui-col-xl-10, .mui-col-xl-11, .mui-col-xl-12 { + float: left; } + .mui-col-xl-1 { + width: 8.33333%; } + .mui-col-xl-2 { + width: 16.66667%; } + .mui-col-xl-3 { + width: 25%; } + .mui-col-xl-4 { + width: 33.33333%; } + .mui-col-xl-5 { + width: 41.66667%; } + .mui-col-xl-6 { + width: 50%; } + .mui-col-xl-7 { + width: 58.33333%; } + .mui-col-xl-8 { + width: 66.66667%; } + .mui-col-xl-9 { + width: 75%; } + .mui-col-xl-10 { + width: 83.33333%; } + .mui-col-xl-11 { + width: 91.66667%; } + .mui-col-xl-12 { + width: 100%; } + .mui-col-xl-offset-0 { + margin-left: 0%; } + .mui-col-xl-offset-1 { + margin-left: 8.33333%; } + .mui-col-xl-offset-2 { + margin-left: 16.66667%; } + .mui-col-xl-offset-3 { + margin-left: 25%; } + .mui-col-xl-offset-4 { + margin-left: 33.33333%; } + .mui-col-xl-offset-5 { + margin-left: 41.66667%; } + .mui-col-xl-offset-6 { + margin-left: 50%; } + .mui-col-xl-offset-7 { + margin-left: 58.33333%; } + .mui-col-xl-offset-8 { + margin-left: 66.66667%; } + .mui-col-xl-offset-9 { + margin-left: 75%; } + .mui-col-xl-offset-10 { + margin-left: 83.33333%; } + .mui-col-xl-offset-11 { + margin-left: 91.66667%; } + .mui-col-xl-offset-12 { + margin-left: 100%; } } + +/** + * MUI Panel module + */ +.mui-panel { + padding: 15px; + margin-bottom: 20px; + border-radius: 0; + background-color: #FFF; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0px 2px 0 rgba(0, 0, 0, 0.12); } + .mui-panel:before, .mui-panel:after { + content: " "; + display: table; } + .mui-panel:after { + clear: both; } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-panel { + box-shadow: 0 -1px 2px 0 rgba(0, 0, 0, 0.12), -1px 0px 2px 0 rgba(0, 0, 0, 0.12), 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0px 2px 0 rgba(0, 0, 0, 0.12); } } + +/** + * MUI Select Component + */ +.mui-select { + display: block; + padding-top: 15px; + margin-bottom: 20px; + position: relative; } + .mui-select:focus { + outline: 0; } + .mui-select:focus > select { + height: 33px; + margin-bottom: -1px; + border-color: #2196F3; + border-width: 2px; } + .mui-select > select { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + display: block; + height: 32px; + width: 100%; + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + outline: none; + border: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.26); + border-radius: 0px; + box-shadow: none; + background-color: transparent; + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNiIgd2lkdGg9IjEwIj48cG9seWdvbiBwb2ludHM9IjAsMCAxMCwwIDUsNiIgc3R5bGU9ImZpbGw6cmdiYSgwLDAsMCwuMjQpOyIvPjwvc3ZnPg=="); + background-repeat: no-repeat; + background-position: right center; + cursor: pointer; + color: rgba(0, 0, 0, 0.87); + font-size: 16px; + padding: 0 25px 0 0; } + .mui-select > select::-ms-expand { + display: none; } + .mui-select > select:focus { + outline: 0; + height: 33px; + margin-bottom: -1px; + border-color: #2196F3; + border-width: 2px; } + .mui-select > select:disabled { + color: rgba(0, 0, 0, 0.38); + cursor: not-allowed; + background-color: transparent; + opacity: 1; } + +.mui-select__menu { + position: absolute; + z-index: 1; + min-width: 100%; + overflow-y: auto; + padding: 8px 0; + background-color: #FFF; + font-size: 16px; } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-select__menu { + border-left: 1px solid rgba(0, 0, 0, 0.12); + border-top: 1px solid rgba(0, 0, 0, 0.12); } } + .mui-select__menu > div { + padding: 0 22px; + height: 42px; + line-height: 42px; + cursor: pointer; + white-space: nowrap; } + .mui-select__menu > div:hover { + background-color: #E0E0E0; } + .mui-select__menu > div.mui--is-selected { + background-color: #EEEEEE; } + +/** + * MUI Table Component + */ +th { + text-align: left; } + +.mui-table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; } + .mui-table > thead > tr > th, + .mui-table > thead > tr > td, + .mui-table > tbody > tr > th, + .mui-table > tbody > tr > td, + .mui-table > tfoot > tr > th, + .mui-table > tfoot > tr > td { + padding: 10px; + line-height: 1.429; } + .mui-table > thead > tr > th { + border-bottom: 2px solid rgba(0, 0, 0, 0.12); + font-weight: 700; } + .mui-table > tbody + tbody { + border-top: 2px solid rgba(0, 0, 0, 0.12); } + .mui-table.mui-table--bordered > tbody > tr > td { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); } + +/** + * MUI Tabs module + */ +.mui-tabs__bar { + list-style: none; + padding-left: 0; + margin-bottom: 0; + background-color: transparent; + white-space: nowrap; + overflow-x: auto; } + .mui-tabs__bar > li { + display: inline-block; } + .mui-tabs__bar > li > a { + display: block; + white-space: nowrap; + text-transform: uppercase; + font-weight: 500; + font-size: 14px; + color: rgba(0, 0, 0, 0.87); + cursor: default; + height: 48px; + line-height: 48px; + padding-left: 24px; + padding-right: 24px; + user-select: none; } + .mui-tabs__bar > li > a:hover { + text-decoration: none; } + .mui-tabs__bar > li.mui--is-active { + border-bottom: 2px solid #2196F3; } + .mui-tabs__bar > li.mui--is-active > a { + color: #2196F3; } + .mui-tabs__bar.mui-tabs__bar--justified { + display: table; + width: 100%; + table-layout: fixed; } + .mui-tabs__bar.mui-tabs__bar--justified > li { + display: table-cell; } + .mui-tabs__bar.mui-tabs__bar--justified > li > a { + text-align: center; + padding-left: 0px; + padding-right: 0px; } + +.mui-tabs__pane { + display: none; } + .mui-tabs__pane.mui--is-active { + display: block; } + +[data-mui-toggle="tab"] { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; } + +/** + * MUI Textfield Component + */ +.mui-textfield { + display: block; + padding-top: 15px; + margin-bottom: 20px; + position: relative; } + .mui-textfield > label { + position: absolute; + top: 0; + display: block; + width: 100%; + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + font-weight: 400; + line-height: 15px; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .mui-textfield > textarea { + padding-top: 5px; } + .mui-textfield > input, + .mui-textfield > textarea { + display: block; } + .mui-textfield > input:focus ~ label, + .mui-textfield > textarea:focus ~ label { + color: #2196F3; } + +.mui-textfield--float-label > label { + position: absolute; + transform: translate(0px, 15px); + font-size: 16px; + line-height: 32px; + color: rgba(0, 0, 0, 0.26); + text-overflow: clip; + cursor: text; + pointer-events: none; } + +.mui-textfield--float-label > input:focus ~ label, +.mui-textfield--float-label > textarea:focus ~ label { + transform: translate(0px, 0px); + font-size: 12px; + line-height: 15px; + text-overflow: ellipsis; } + +.mui-textfield--float-label > input:not(:focus).mui--is-not-empty ~ label, .mui-textfield--float-label > input:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, .mui-textfield--float-label > input:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield--float-label > textarea:not(:focus).mui--is-not-empty ~ label, +.mui-textfield--float-label > textarea:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield--float-label > textarea:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label { + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + line-height: 15px; + transform: translate(0px, 0px); + text-overflow: ellipsis; } + +.mui-textfield--wrap-label { + display: table; + width: 100%; + padding-top: 0px; } + .mui-textfield--wrap-label:not(.mui-textfield--float-label) > label { + display: table-header-group; + position: static; + white-space: normal; + overflow-x: visible; } + +.mui-textfield > input, +.mui-textfield > textarea { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + display: block; + background-color: transparent; + color: rgba(0, 0, 0, 0.87); + border: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.26); + outline: none; + width: 100%; + font-size: 16px; + padding: 0; + box-shadow: none; + border-radius: 0px; + background-image: none; } + .mui-textfield > input:focus, + .mui-textfield > textarea:focus { + border-color: #2196F3; + border-width: 2px; } + .mui-textfield > input:disabled, .mui-textfield > input:read-only, + .mui-textfield > textarea:disabled, + .mui-textfield > textarea:read-only { + cursor: not-allowed; + background-color: transparent; + opacity: 1; } + .mui-textfield > input::placeholder, + .mui-textfield > textarea::placeholder { + color: rgba(0, 0, 0, 0.26); + opacity: 1; } + +.mui-textfield > input { + height: 32px; } + .mui-textfield > input:focus { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > textarea { + min-height: 64px; } + .mui-textfield > textarea[rows]:not([rows="2"]):focus { + margin-bottom: -1px; } + +.mui-textfield > input:focus { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > input:invalid:not(:focus):not(:required), .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty, .mui-textfield > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:invalid:not(:focus):not(:required), +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-not-empty, +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, +.mui-textfield > textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) { + border-color: #F44336; + border-width: 2px; } + +.mui-textfield > input:invalid:not(:focus):not(:required), .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty, .mui-textfield > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > input:invalid:not(:focus):not(:required) ~ label, .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty ~ label, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:invalid:not(:focus):not(:required) ~ label, +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-not-empty ~ label, +.mui-textfield > textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:not(:required) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label { + color: #F44336; } + +.mui-textfield:not(.mui-textfield--float-label) > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty ~ label { + color: #F44336; } + +/** + * MUI Helpers module + */ +@keyframes mui-node-inserted { + from { + opacity: 0.99; } + to { + opacity: 1; } } + +.mui--no-transition { + transition: none !important; } + +.mui--no-user-select { + user-select: none; } + +.mui-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; } + +.mui--text-left { + text-align: left !important; } + +.mui--text-right { + text-align: right !important; } + +.mui--text-center { + text-align: center !important; } + +.mui--text-justify { + text-align: justify !important; } + +.mui--text-nowrap { + white-space: nowrap !important; } + +.mui--align-baseline { + vertical-align: baseline !important; } + +.mui--align-top { + vertical-align: top !important; } + +.mui--align-middle { + vertical-align: middle !important; } + +.mui--align-bottom { + vertical-align: bottom !important; } + +.mui--text-dark { + color: rgba(0, 0, 0, 0.87); } + +.mui--text-dark-secondary { + color: rgba(0, 0, 0, 0.54); } + +.mui--text-dark-hint { + color: rgba(0, 0, 0, 0.38); } + +.mui--text-light { + color: #FFF; } + +.mui--text-light-secondary { + color: rgba(255, 255, 255, 0.7); } + +.mui--text-light-hint { + color: rgba(255, 255, 255, 0.3); } + +.mui--text-accent { + color: rgba(186, 214, 73, 0.87); } + +.mui--text-accent-secondary { + color: rgba(186, 214, 73, 0.54); } + +.mui--text-accent-hint { + color: rgba(186, 214, 73, 0.38); } + +.mui--text-black { + color: #000; } + +.mui--text-white { + color: #FFF; } + +.mui--text-danger { + color: #F44336; } + +.mui-list--unstyled { + padding-left: 0; + list-style: none; } + +.mui-list--inline { + padding-left: 0; + list-style: none; + margin-left: -5px; } + .mui-list--inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; } + +.mui--z1, .mui-dropdown__menu, .mui-select__menu { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); } + +.mui--z2 { + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); } + +.mui--z3 { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + +.mui--z4 { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); } + +.mui--z5 { + box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22); } + +.mui--clearfix:before, .mui--clearfix:after { + content: " "; + display: table; } + +.mui--clearfix:after { + clear: both; } + +.mui--pull-right { + float: right !important; } + +.mui--pull-left { + float: left !important; } + +.mui--hide { + display: none !important; } + +.mui--show { + display: block !important; } + +.mui--invisible { + visibility: hidden; } + +.mui--overflow-hidden { + overflow: hidden !important; } + +.mui--overflow-hidden-x { + overflow-x: hidden !important; } + +.mui--overflow-hidden-y { + overflow-y: hidden !important; } + +.mui--visible-xs-block, +.mui--visible-xs-inline, +.mui--visible-xs-inline-block, +.mui--visible-sm-block, +.mui--visible-sm-inline, +.mui--visible-sm-inline-block, +.mui--visible-md-block, +.mui--visible-md-inline, +.mui--visible-md-inline-block, +.mui--visible-lg-block, +.mui--visible-lg-inline, +.mui--visible-lg-inline-block, +.mui--visible-xl-block, +.mui--visible-xl-inline, +.mui--visible-xl-inline-block { + display: none !important; } + +@media (max-width: 543px) { + .mui-visible-xs { + display: block !important; } + table.mui-visible-xs { + display: table; } + tr.mui-visible-xs { + display: table-row !important; } + th.mui-visible-xs, + td.mui-visible-xs { + display: table-cell !important; } + .mui--visible-xs-block { + display: block !important; } + .mui--visible-xs-inline { + display: inline !important; } + .mui--visible-xs-inline-block { + display: inline-block !important; } } + +@media (min-width: 544px) and (max-width: 767px) { + .mui-visible-sm { + display: block !important; } + table.mui-visible-sm { + display: table; } + tr.mui-visible-sm { + display: table-row !important; } + th.mui-visible-sm, + td.mui-visible-sm { + display: table-cell !important; } + .mui--visible-sm-block { + display: block !important; } + .mui--visible-sm-inline { + display: inline !important; } + .mui--visible-sm-inline-block { + display: inline-block !important; } } + +@media (min-width: 768px) and (max-width: 991px) { + .mui-visible-md { + display: block !important; } + table.mui-visible-md { + display: table; } + tr.mui-visible-md { + display: table-row !important; } + th.mui-visible-md, + td.mui-visible-md { + display: table-cell !important; } + .mui--visible-md-block { + display: block !important; } + .mui--visible-md-inline { + display: inline !important; } + .mui--visible-md-inline-block { + display: inline-block !important; } } + +@media (min-width: 992px) and (max-width: 1199px) { + .mui-visible-lg { + display: block !important; } + table.mui-visible-lg { + display: table; } + tr.mui-visible-lg { + display: table-row !important; } + th.mui-visible-lg, + td.mui-visible-lg { + display: table-cell !important; } + .mui--visible-lg-block { + display: block !important; } + .mui--visible-lg-inline { + display: inline !important; } + .mui--visible-lg-inline-block { + display: inline-block !important; } } + +@media (min-width: 1200px) { + .mui-visible-xl { + display: block !important; } + table.mui-visible-xl { + display: table; } + tr.mui-visible-xl { + display: table-row !important; } + th.mui-visible-xl, + td.mui-visible-xl { + display: table-cell !important; } + .mui--visible-xl-block { + display: block !important; } + .mui--visible-xl-inline { + display: inline !important; } + .mui--visible-xl-inline-block { + display: inline-block !important; } } + +@media (max-width: 543px) { + .mui--hidden-xs { + display: none !important; } } + +@media (min-width: 544px) and (max-width: 767px) { + .mui--hidden-sm { + display: none !important; } } + +@media (min-width: 768px) and (max-width: 991px) { + .mui--hidden-md { + display: none !important; } } + +@media (min-width: 992px) and (max-width: 1199px) { + .mui--hidden-lg { + display: none !important; } } + +@media (min-width: 1200px) { + .mui--hidden-xl { + display: none !important; } } + +body.mui-body--scroll-lock { + overflow: hidden !important; } + +/** + * MUI Overlay module + */ +#mui-overlay { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99999999; + background-color: rgba(0, 0, 0, 0.2); + overflow: auto; } + +/** + * MUI Ripple module + */ +.mui-ripple-effect { + position: absolute; + border-radius: 50%; + pointer-events: none; + opacity: 0; + animation: mui-ripple-animation 2s; } + +@keyframes mui-ripple-animation { + from { + transform: scale(1); + opacity: 0.4; } + to { + transform: scale(100); + opacity: 0; } } + +.mui-btn > .mui-ripple-effect { + background-color: #a6a6a6; } + +.mui-btn--primary > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--dark > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--danger > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--accent > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--flat > .mui-ripple-effect { + background-color: #a6a6a6; } + +/** + * MUI Typography module + */ +.mui--text-display4 { + font-weight: 300; + font-size: 112px; + line-height: 112px; } + +.mui--text-display3 { + font-weight: 400; + font-size: 56px; + line-height: 56px; } + +.mui--text-display2 { + font-weight: 400; + font-size: 45px; + line-height: 48px; } + +.mui--text-display1, h1 { + font-weight: 400; + font-size: 34px; + line-height: 40px; } + +.mui--text-headline, h2 { + font-weight: 400; + font-size: 24px; + line-height: 32px; } + +.mui--text-title, h3 { + font-weight: 400; + font-size: 20px; + line-height: 28px; } + +.mui--text-subhead, h4 { + font-weight: 400; + font-size: 16px; + line-height: 24px; } + +.mui--text-body2, h5 { + font-weight: 500; + font-size: 14px; + line-height: 24px; } + +.mui--text-body1 { + font-weight: 400; + font-size: 14px; + line-height: 20px; } + +.mui--text-caption { + font-weight: 400; + font-size: 12px; + line-height: 16px; } + +.mui--text-menu { + font-weight: 500; + font-size: 13px; + line-height: 17px; } + +.mui--text-button { + font-weight: 500; + font-size: 14px; + line-height: 18px; + text-transform: uppercase; } + diff --git a/mdot/mdot_server/mdot_server/app/css/mui.custom.css b/mdot/mdot_server/mdot_server/app/css/mui.custom.css new file mode 100644 index 0000000..cfe1de1 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/mui.custom.css @@ -0,0 +1,1912 @@ +/** + * MUI Colors module + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ +html { + font-family: sans-serif; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/** + * Remove default margin. + */ +body { + margin: 0; } + +/* HTML5 display definitions + ========================================================================== */ +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; } + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ +audio, +canvas, +progress, +video { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ } + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +audio:not([controls]) { + display: none; + height: 0; } + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ +[hidden], +template { + display: none; } + +/* Links + ========================================================================== */ +/** + * Remove the gray background color from active links in IE 10. + */ +a { + background-color: transparent; } + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ +a:active, +a:hover { + outline: 0; } + +/* Text-level semantics + ========================================================================== */ +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ +abbr[title] { + border-bottom: 1px dotted; } + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ +b, +strong { + font-weight: bold; } + +/** + * Address styling not present in Safari and Chrome. + */ +dfn { + font-style: italic; } + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/** + * Address styling not present in IE 8/9. + */ +mark { + background: #ff0; + color: #000; } + +/** + * Address inconsistent and variable font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +/* Embedded content + ========================================================================== */ +/** + * Remove border when inside `a` element in IE 8/9/10. + */ +img { + border: 0; } + +/** + * Correct overflow not hidden in IE 9/10/11. + */ +svg:not(:root) { + overflow: hidden; } + +/* Grouping content + ========================================================================== */ +/** + * Address margin not present in IE 8/9 and Safari. + */ +figure { + margin: 1em 40px; } + +/** + * Address differences between Firefox and other browsers. + */ +hr { + box-sizing: content-box; + height: 0; } + +/** + * Contain overflow in all browsers. + */ +pre { + overflow: auto; } + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; } + +/* Forms + ========================================================================== */ +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ +button, +input, +optgroup, +select, +textarea { + color: inherit; + /* 1 */ + font: inherit; + /* 2 */ + margin: 0; + /* 3 */ } + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ +button { + overflow: visible; } + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ +button, +select { + text-transform: none; } + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ } + +/** + * Re-set default cursor for disabled elements. + */ +button[disabled], +html input[disabled] { + cursor: default; } + +/** + * Remove inner padding and border in Firefox 4+. + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; } + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ +input { + line-height: normal; } + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + box-sizing: content-box; + /* 2 */ } + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * Define consistent border, margin, and padding. + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; } + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ +textarea { + overflow: auto; } + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ +optgroup { + font-weight: bold; } + +/* Tables + ========================================================================== */ +/** + * Remove most spacing between table cells. + */ +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; } + +/** + * MUI Colors module + */ +/** + * MUI Reboot + */ +* { + box-sizing: border-box; } + +*:before, +*:after { + box-sizing: border-box; } + +html { + font-size: 10px; + -webkit-tap-highlight-color: transparent; } + +body { + font-family: Arial, Verdana, Tahoma; + font-size: 14px; + font-weight: 400; + line-height: 1.429; + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; } + +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; } + +a { + color: #2196F3; + text-decoration: none; } + a:hover, a:focus { + color: #1976D2; + text-decoration: underline; } + a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; } + +p { + margin: 0 0 10px; } + +ul, +ol { + margin-top: 0; + margin-bottom: 10px; } + +figure { + margin: 0; } + +img { + vertical-align: middle; } + +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + height: 1px; + background-color: rgba(0, 0, 0, 0.12); } + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 10px; + font-size: 21px; + color: rgba(0, 0, 0, 0.87); + line-height: inherit; + border: 0; } + +input[type="search"] { + box-sizing: border-box; + -webkit-appearance: none; } + +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; } + +input[type="radio"]:disabled, +input[type="checkbox"]:disabled { + cursor: not-allowed; } + +strong { + font-weight: 700; } + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #2196F3; } + +h1, h2, h3 { + margin-top: 20px; + margin-bottom: 10px; } + +h4, h5, h6 { + margin-top: 10px; + margin-bottom: 10px; } + +/** + * MUI Appbar + */ +.mui--appbar-height { + height: 56px; } + +.mui--appbar-min-height, .mui-appbar { + min-height: 56px; } + +.mui--appbar-line-height { + line-height: 56px; } + +.mui--appbar-top { + top: 56px; } + +@media (orientation: landscape) and (max-height: 480px) { + .mui--appbar-height { + height: 48px; } + .mui--appbar-min-height, .mui-appbar { + min-height: 48px; } + .mui--appbar-line-height { + line-height: 48px; } + .mui--appbar-top { + top: 48px; } } + +@media (min-width: 480px) { + .mui--appbar-height { + height: 64px; } + .mui--appbar-min-height, .mui-appbar { + min-height: 64px; } + .mui--appbar-line-height { + line-height: 64px; } + .mui--appbar-top { + top: 64px; } } + +.mui-appbar { + background-color: #2196F3; + color: #FFF; } + +/** + * MUI Buttons + */ +.mui-btn { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + font-weight: 500; + font-size: 14px; + line-height: 18px; + text-transform: uppercase; + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; + transition: all 0.2s ease-in-out; + display: inline-block; + height: 36px; + padding: 0 26px; + margin-top: 6px; + margin-bottom: 6px; + border: none; + border-radius: 2px; + cursor: pointer; + touch-action: manipulation; + background-image: none; + text-align: center; + line-height: 36px; + vertical-align: middle; + white-space: nowrap; + user-select: none; + font-size: 14px; + letter-spacing: 0.03em; + position: relative; + overflow: hidden; } + .mui-btn:hover, .mui-btn:focus, .mui-btn:active { + color: rgba(0, 0, 0, 0.87); + background-color: white; } + .mui-btn[disabled]:hover, .mui-btn[disabled]:focus, .mui-btn[disabled]:active { + color: rgba(0, 0, 0, 0.87); + background-color: #FFF; } + .mui-btn.mui-btn--flat { + color: rgba(0, 0, 0, 0.87); + background-color: transparent; } + .mui-btn.mui-btn--flat:hover, .mui-btn.mui-btn--flat:focus, .mui-btn.mui-btn--flat:active { + color: rgba(0, 0, 0, 0.87); + background-color: #f2f2f2; } + .mui-btn.mui-btn--flat[disabled]:hover, .mui-btn.mui-btn--flat[disabled]:focus, .mui-btn.mui-btn--flat[disabled]:active { + color: rgba(0, 0, 0, 0.87); + background-color: transparent; } + .mui-btn:hover, .mui-btn:focus, .mui-btn:active { + outline: 0; + text-decoration: none; + color: rgba(0, 0, 0, 0.87); } + .mui-btn:hover, .mui-btn:focus { + box-shadow: 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn:hover, .mui-btn:focus { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } } + .mui-btn:active { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn:active { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } } + .mui-btn:disabled, .mui-btn.mui--is-disabled { + cursor: not-allowed; + pointer-events: none; + opacity: 0.60; + box-shadow: none; } + +.mui-btn + .mui-btn { + margin-left: 8px; } + +.mui-btn--flat { + background-color: transparent; } + .mui-btn--flat:hover, .mui-btn--flat:focus, .mui-btn--flat:active { + box-shadow: none; + background-color: #f2f2f2; } + +.mui-btn--raised, .mui-btn--fab { + box-shadow: 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn--raised, .mui-btn--fab { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 0px 2px rgba(0, 0, 0, 0.12), 0 2px 2px rgba(0, 0, 0, 0.2); } } + .mui-btn--raised:active, .mui-btn--fab:active { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-btn--raised:active, .mui-btn--fab:active { + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.12), -1px 0px 2px rgba(0, 0, 0, 0.12), 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } } + +.mui-btn--fab { + position: relative; + padding: 0; + width: 55px; + height: 55px; + line-height: 55px; + border-radius: 50%; + z-index: 1; } + +.mui-btn--primary { + color: #FFF; + background-color: #2196F3; } + .mui-btn--primary:hover, .mui-btn--primary:focus, .mui-btn--primary:active { + color: #FFF; + background-color: #39a1f4; } + .mui-btn--primary[disabled]:hover, .mui-btn--primary[disabled]:focus, .mui-btn--primary[disabled]:active { + color: #FFF; + background-color: #2196F3; } + .mui-btn--primary.mui-btn--flat { + color: #2196F3; + background-color: transparent; } + .mui-btn--primary.mui-btn--flat:hover, .mui-btn--primary.mui-btn--flat:focus, .mui-btn--primary.mui-btn--flat:active { + color: #2196F3; + background-color: #f2f2f2; } + .mui-btn--primary.mui-btn--flat[disabled]:hover, .mui-btn--primary.mui-btn--flat[disabled]:focus, .mui-btn--primary.mui-btn--flat[disabled]:active { + color: #2196F3; + background-color: transparent; } + +.mui-btn--dark { + color: #FFF; + background-color: #424242; } + .mui-btn--dark:hover, .mui-btn--dark:focus, .mui-btn--dark:active { + color: #FFF; + background-color: #4f4f4f; } + .mui-btn--dark[disabled]:hover, .mui-btn--dark[disabled]:focus, .mui-btn--dark[disabled]:active { + color: #FFF; + background-color: #424242; } + .mui-btn--dark.mui-btn--flat { + color: #424242; + background-color: transparent; } + .mui-btn--dark.mui-btn--flat:hover, .mui-btn--dark.mui-btn--flat:focus, .mui-btn--dark.mui-btn--flat:active { + color: #424242; + background-color: #f2f2f2; } + .mui-btn--dark.mui-btn--flat[disabled]:hover, .mui-btn--dark.mui-btn--flat[disabled]:focus, .mui-btn--dark.mui-btn--flat[disabled]:active { + color: #424242; + background-color: transparent; } + +.mui-btn--danger { + color: #FFF; + background-color: #F44336; } + .mui-btn--danger:hover, .mui-btn--danger:focus, .mui-btn--danger:active { + color: #FFF; + background-color: #f55a4e; } + .mui-btn--danger[disabled]:hover, .mui-btn--danger[disabled]:focus, .mui-btn--danger[disabled]:active { + color: #FFF; + background-color: #F44336; } + .mui-btn--danger.mui-btn--flat { + color: #F44336; + background-color: transparent; } + .mui-btn--danger.mui-btn--flat:hover, .mui-btn--danger.mui-btn--flat:focus, .mui-btn--danger.mui-btn--flat:active { + color: #F44336; + background-color: #f2f2f2; } + .mui-btn--danger.mui-btn--flat[disabled]:hover, .mui-btn--danger.mui-btn--flat[disabled]:focus, .mui-btn--danger.mui-btn--flat[disabled]:active { + color: #F44336; + background-color: transparent; } + +.mui-btn--accent { + color: #004c6d; + background-color: #bad649; } + .mui-btn--accent:hover, .mui-btn--accent:focus, .mui-btn--accent:active { + color: #004c6d; + background-color: #c2db5e; } + .mui-btn--accent[disabled]:hover, .mui-btn--accent[disabled]:focus, .mui-btn--accent[disabled]:active { + color: #004c6d; + background-color: #bad649; } + .mui-btn--accent.mui-btn--flat { + color: #bad649; + background-color: transparent; } + .mui-btn--accent.mui-btn--flat:hover, .mui-btn--accent.mui-btn--flat:focus, .mui-btn--accent.mui-btn--flat:active { + color: #bad649; + background-color: #f2f2f2; } + .mui-btn--accent.mui-btn--flat[disabled]:hover, .mui-btn--accent.mui-btn--flat[disabled]:focus, .mui-btn--accent.mui-btn--flat[disabled]:active { + color: #bad649; + background-color: transparent; } + +.mui-btn--small { + height: 30.6px; + line-height: 30.6px; + padding: 0 16px; + font-size: 13px; } + +.mui-btn--large { + height: 54px; + line-height: 54px; + padding: 0 26px; + font-size: 14px; } + +.mui-btn--fab.mui-btn--small { + width: 44px; + height: 44px; + line-height: 44px; } + +.mui-btn--fab.mui-btn--large { + width: 75px; + height: 75px; + line-height: 75px; } + +/** + * MUI Checkboxe and Radio Components + */ +.mui-radio, +.mui-checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; } + .mui-radio > label, + .mui-checkbox > label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; } + +.mui-radio > label > input[type="radio"], +.mui-radio--inline > label > input[type="radio"], +.mui-checkbox > label > input[type="checkbox"], +.mui-checkbox--inline > label > input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px; } + +.mui-radio + .mui-radio, +.mui-checkbox + .mui-checkbox { + margin-top: -5px; } + +.mui-radio--inline, +.mui-checkbox--inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; } + .mui-radio--inline > input[type="radio"], + .mui-radio--inline > input[type="checkbox"], + .mui-radio--inline > label > input[type="radio"], + .mui-radio--inline > label > input[type="checkbox"], + .mui-checkbox--inline > input[type="radio"], + .mui-checkbox--inline > input[type="checkbox"], + .mui-checkbox--inline > label > input[type="radio"], + .mui-checkbox--inline > label > input[type="checkbox"] { + margin: 4px 0 0; + line-height: normal; } + +.mui-radio--inline + .mui-radio--inline, +.mui-checkbox--inline + .mui-checkbox--inline { + margin-top: 0; + margin-left: 10px; } + +/** + * MUI Container module + */ +.mui-container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; } + .mui-container:before, .mui-container:after { + content: " "; + display: table; } + .mui-container:after { + clear: both; } + @media (min-width: 544px) { + .mui-container { + max-width: 570px; } } + @media (min-width: 768px) { + .mui-container { + max-width: 740px; } } + @media (min-width: 992px) { + .mui-container { + max-width: 960px; } } + @media (min-width: 1200px) { + .mui-container { + max-width: 1170px; } } + +.mui-container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; } + .mui-container-fluid:before, .mui-container-fluid:after { + content: " "; + display: table; } + .mui-container-fluid:after { + clear: both; } + +/** + * MUI Divider Component and CSS Helpers + */ +.mui-divider { + display: block; + height: 1px; + background-color: rgba(0, 0, 0, 0.12); } + +.mui--divider-top { + border-top: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-bottom { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-left { + border-left: 1px solid rgba(0, 0, 0, 0.12); } + +.mui--divider-right { + border-right: 1px solid rgba(0, 0, 0, 0.12); } + +/** + * MUI Dropdown module + */ +.mui-dropdown { + display: inline-block; + position: relative; } + +[data-mui-toggle="dropdown"] { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + outline: 0; } + +.mui-dropdown__menu { + position: absolute; + top: 100%; + left: 0; + display: none; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + text-align: left; + background-color: #FFF; + border-radius: 2px; + z-index: 1; + background-clip: padding-box; } + .mui-dropdown__menu.mui--is-open { + display: block; } + .mui-dropdown__menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.429; + color: rgba(0, 0, 0, 0.87); + white-space: nowrap; } + .mui-dropdown__menu > li > a:hover, .mui-dropdown__menu > li > a:focus { + text-decoration: none; + color: rgba(0, 0, 0, 0.87); + background-color: #EEEEEE; } + .mui-dropdown__menu > .mui--is-disabled > a, .mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus { + color: #EEEEEE; } + .mui-dropdown__menu > .mui--is-disabled > a:hover, .mui-dropdown__menu > .mui--is-disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + cursor: not-allowed; } + +.mui-dropdown__menu--right { + left: auto; + right: 0; } + +/** + * MUI Form Component + */ +@media (min-width: 544px) { + .mui-form--inline > .mui-textfield { + display: inline-block; + margin-bottom: 0; } + .mui-form--inline > .mui-radio, + .mui-form--inline > .mui-checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; } + .mui-form--inline > .mui-radio > label, + .mui-form--inline > .mui-checkbox > label { + padding-left: 0; } + .mui-form--inline > .mui-radio > label > input[type="radio"], + .mui-form--inline > .mui-checkbox > label > input[type="checkbox"] { + position: relative; + margin-left: 0; } + .mui-form--inline > .mui-select { + display: inline-block; } + .mui-form--inline > .mui-btn { + margin-bottom: 0; + margin-top: 0; + vertical-align: bottom; } } + +/** + * MUI Grid module + */ +.mui-row { + margin-left: -15px; + margin-right: -15px; } + .mui-row:before, .mui-row:after { + content: " "; + display: table; } + .mui-row:after { + clear: both; } + +.mui-col-xs-1, .mui-col-sm-1, .mui-col-md-1, .mui-col-lg-1, .mui-col-xs-2, .mui-col-sm-2, .mui-col-md-2, .mui-col-lg-2, .mui-col-xs-3, .mui-col-sm-3, .mui-col-md-3, .mui-col-lg-3, .mui-col-xs-4, .mui-col-sm-4, .mui-col-md-4, .mui-col-lg-4, .mui-col-xs-5, .mui-col-sm-5, .mui-col-md-5, .mui-col-lg-5, .mui-col-xs-6, .mui-col-sm-6, .mui-col-md-6, .mui-col-lg-6, .mui-col-xs-7, .mui-col-sm-7, .mui-col-md-7, .mui-col-lg-7, .mui-col-xs-8, .mui-col-sm-8, .mui-col-md-8, .mui-col-lg-8, .mui-col-xs-9, .mui-col-sm-9, .mui-col-md-9, .mui-col-lg-9, .mui-col-xs-10, .mui-col-sm-10, .mui-col-md-10, .mui-col-lg-10, .mui-col-xs-11, .mui-col-sm-11, .mui-col-md-11, .mui-col-lg-11, .mui-col-xs-12, .mui-col-sm-12, .mui-col-md-12, .mui-col-lg-12 { + min-height: 1px; + padding-left: 15px; + padding-right: 15px; } + +.mui-col-xs-1, .mui-col-xs-2, .mui-col-xs-3, .mui-col-xs-4, .mui-col-xs-5, .mui-col-xs-6, .mui-col-xs-7, .mui-col-xs-8, .mui-col-xs-9, .mui-col-xs-10, .mui-col-xs-11, .mui-col-xs-12 { + float: left; } + +.mui-col-xs-1 { + width: 8.33333%; } + +.mui-col-xs-2 { + width: 16.66667%; } + +.mui-col-xs-3 { + width: 25%; } + +.mui-col-xs-4 { + width: 33.33333%; } + +.mui-col-xs-5 { + width: 41.66667%; } + +.mui-col-xs-6 { + width: 50%; } + +.mui-col-xs-7 { + width: 58.33333%; } + +.mui-col-xs-8 { + width: 66.66667%; } + +.mui-col-xs-9 { + width: 75%; } + +.mui-col-xs-10 { + width: 83.33333%; } + +.mui-col-xs-11 { + width: 91.66667%; } + +.mui-col-xs-12 { + width: 100%; } + +.mui-col-xs-offset-0 { + margin-left: 0%; } + +.mui-col-xs-offset-1 { + margin-left: 8.33333%; } + +.mui-col-xs-offset-2 { + margin-left: 16.66667%; } + +.mui-col-xs-offset-3 { + margin-left: 25%; } + +.mui-col-xs-offset-4 { + margin-left: 33.33333%; } + +.mui-col-xs-offset-5 { + margin-left: 41.66667%; } + +.mui-col-xs-offset-6 { + margin-left: 50%; } + +.mui-col-xs-offset-7 { + margin-left: 58.33333%; } + +.mui-col-xs-offset-8 { + margin-left: 66.66667%; } + +.mui-col-xs-offset-9 { + margin-left: 75%; } + +.mui-col-xs-offset-10 { + margin-left: 83.33333%; } + +.mui-col-xs-offset-11 { + margin-left: 91.66667%; } + +.mui-col-xs-offset-12 { + margin-left: 100%; } + +@media (min-width: 544px) { + .mui-col-sm-1, .mui-col-sm-2, .mui-col-sm-3, .mui-col-sm-4, .mui-col-sm-5, .mui-col-sm-6, .mui-col-sm-7, .mui-col-sm-8, .mui-col-sm-9, .mui-col-sm-10, .mui-col-sm-11, .mui-col-sm-12 { + float: left; } + .mui-col-sm-1 { + width: 8.33333%; } + .mui-col-sm-2 { + width: 16.66667%; } + .mui-col-sm-3 { + width: 25%; } + .mui-col-sm-4 { + width: 33.33333%; } + .mui-col-sm-5 { + width: 41.66667%; } + .mui-col-sm-6 { + width: 50%; } + .mui-col-sm-7 { + width: 58.33333%; } + .mui-col-sm-8 { + width: 66.66667%; } + .mui-col-sm-9 { + width: 75%; } + .mui-col-sm-10 { + width: 83.33333%; } + .mui-col-sm-11 { + width: 91.66667%; } + .mui-col-sm-12 { + width: 100%; } + .mui-col-sm-offset-0 { + margin-left: 0%; } + .mui-col-sm-offset-1 { + margin-left: 8.33333%; } + .mui-col-sm-offset-2 { + margin-left: 16.66667%; } + .mui-col-sm-offset-3 { + margin-left: 25%; } + .mui-col-sm-offset-4 { + margin-left: 33.33333%; } + .mui-col-sm-offset-5 { + margin-left: 41.66667%; } + .mui-col-sm-offset-6 { + margin-left: 50%; } + .mui-col-sm-offset-7 { + margin-left: 58.33333%; } + .mui-col-sm-offset-8 { + margin-left: 66.66667%; } + .mui-col-sm-offset-9 { + margin-left: 75%; } + .mui-col-sm-offset-10 { + margin-left: 83.33333%; } + .mui-col-sm-offset-11 { + margin-left: 91.66667%; } + .mui-col-sm-offset-12 { + margin-left: 100%; } } + +@media (min-width: 768px) { + .mui-col-md-1, .mui-col-md-2, .mui-col-md-3, .mui-col-md-4, .mui-col-md-5, .mui-col-md-6, .mui-col-md-7, .mui-col-md-8, .mui-col-md-9, .mui-col-md-10, .mui-col-md-11, .mui-col-md-12 { + float: left; } + .mui-col-md-1 { + width: 8.33333%; } + .mui-col-md-2 { + width: 16.66667%; } + .mui-col-md-3 { + width: 25%; } + .mui-col-md-4 { + width: 33.33333%; } + .mui-col-md-5 { + width: 41.66667%; } + .mui-col-md-6 { + width: 50%; } + .mui-col-md-7 { + width: 58.33333%; } + .mui-col-md-8 { + width: 66.66667%; } + .mui-col-md-9 { + width: 75%; } + .mui-col-md-10 { + width: 83.33333%; } + .mui-col-md-11 { + width: 91.66667%; } + .mui-col-md-12 { + width: 100%; } + .mui-col-md-offset-0 { + margin-left: 0%; } + .mui-col-md-offset-1 { + margin-left: 8.33333%; } + .mui-col-md-offset-2 { + margin-left: 16.66667%; } + .mui-col-md-offset-3 { + margin-left: 25%; } + .mui-col-md-offset-4 { + margin-left: 33.33333%; } + .mui-col-md-offset-5 { + margin-left: 41.66667%; } + .mui-col-md-offset-6 { + margin-left: 50%; } + .mui-col-md-offset-7 { + margin-left: 58.33333%; } + .mui-col-md-offset-8 { + margin-left: 66.66667%; } + .mui-col-md-offset-9 { + margin-left: 75%; } + .mui-col-md-offset-10 { + margin-left: 83.33333%; } + .mui-col-md-offset-11 { + margin-left: 91.66667%; } + .mui-col-md-offset-12 { + margin-left: 100%; } } + +@media (min-width: 992px) { + .mui-col-lg-1, .mui-col-lg-2, .mui-col-lg-3, .mui-col-lg-4, .mui-col-lg-5, .mui-col-lg-6, .mui-col-lg-7, .mui-col-lg-8, .mui-col-lg-9, .mui-col-lg-10, .mui-col-lg-11, .mui-col-lg-12 { + float: left; } + .mui-col-lg-1 { + width: 8.33333%; } + .mui-col-lg-2 { + width: 16.66667%; } + .mui-col-lg-3 { + width: 25%; } + .mui-col-lg-4 { + width: 33.33333%; } + .mui-col-lg-5 { + width: 41.66667%; } + .mui-col-lg-6 { + width: 50%; } + .mui-col-lg-7 { + width: 58.33333%; } + .mui-col-lg-8 { + width: 66.66667%; } + .mui-col-lg-9 { + width: 75%; } + .mui-col-lg-10 { + width: 83.33333%; } + .mui-col-lg-11 { + width: 91.66667%; } + .mui-col-lg-12 { + width: 100%; } + .mui-col-lg-offset-0 { + margin-left: 0%; } + .mui-col-lg-offset-1 { + margin-left: 8.33333%; } + .mui-col-lg-offset-2 { + margin-left: 16.66667%; } + .mui-col-lg-offset-3 { + margin-left: 25%; } + .mui-col-lg-offset-4 { + margin-left: 33.33333%; } + .mui-col-lg-offset-5 { + margin-left: 41.66667%; } + .mui-col-lg-offset-6 { + margin-left: 50%; } + .mui-col-lg-offset-7 { + margin-left: 58.33333%; } + .mui-col-lg-offset-8 { + margin-left: 66.66667%; } + .mui-col-lg-offset-9 { + margin-left: 75%; } + .mui-col-lg-offset-10 { + margin-left: 83.33333%; } + .mui-col-lg-offset-11 { + margin-left: 91.66667%; } + .mui-col-lg-offset-12 { + margin-left: 100%; } } + +@media (min-width: 1200px) { + .mui-col-xl-1, .mui-col-xl-2, .mui-col-xl-3, .mui-col-xl-4, .mui-col-xl-5, .mui-col-xl-6, .mui-col-xl-7, .mui-col-xl-8, .mui-col-xl-9, .mui-col-xl-10, .mui-col-xl-11, .mui-col-xl-12 { + float: left; } + .mui-col-xl-1 { + width: 8.33333%; } + .mui-col-xl-2 { + width: 16.66667%; } + .mui-col-xl-3 { + width: 25%; } + .mui-col-xl-4 { + width: 33.33333%; } + .mui-col-xl-5 { + width: 41.66667%; } + .mui-col-xl-6 { + width: 50%; } + .mui-col-xl-7 { + width: 58.33333%; } + .mui-col-xl-8 { + width: 66.66667%; } + .mui-col-xl-9 { + width: 75%; } + .mui-col-xl-10 { + width: 83.33333%; } + .mui-col-xl-11 { + width: 91.66667%; } + .mui-col-xl-12 { + width: 100%; } + .mui-col-xl-offset-0 { + margin-left: 0%; } + .mui-col-xl-offset-1 { + margin-left: 8.33333%; } + .mui-col-xl-offset-2 { + margin-left: 16.66667%; } + .mui-col-xl-offset-3 { + margin-left: 25%; } + .mui-col-xl-offset-4 { + margin-left: 33.33333%; } + .mui-col-xl-offset-5 { + margin-left: 41.66667%; } + .mui-col-xl-offset-6 { + margin-left: 50%; } + .mui-col-xl-offset-7 { + margin-left: 58.33333%; } + .mui-col-xl-offset-8 { + margin-left: 66.66667%; } + .mui-col-xl-offset-9 { + margin-left: 75%; } + .mui-col-xl-offset-10 { + margin-left: 83.33333%; } + .mui-col-xl-offset-11 { + margin-left: 91.66667%; } + .mui-col-xl-offset-12 { + margin-left: 100%; } } + +/** + * MUI Panel module + */ +.mui-panel { + padding: 15px; + margin-bottom: 20px; + border-radius: 0; + background-color: #FFF; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0px 2px 0 rgba(0, 0, 0, 0.12); } + .mui-panel:before, .mui-panel:after { + content: " "; + display: table; } + .mui-panel:after { + clear: both; } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-panel { + box-shadow: 0 -1px 2px 0 rgba(0, 0, 0, 0.12), -1px 0px 2px 0 rgba(0, 0, 0, 0.12), 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0px 2px 0 rgba(0, 0, 0, 0.12); } } + +/** + * MUI Select Component + */ +.mui-select { + display: block; + padding-top: 15px; + margin-bottom: 20px; + position: relative; } + .mui-select:focus { + outline: 0; } + .mui-select:focus > select { + height: 33px; + margin-bottom: -1px; + border-color: #2196F3; + border-width: 2px; } + .mui-select > select { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + display: block; + height: 32px; + width: 100%; + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + outline: none; + border: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.26); + border-radius: 0px; + box-shadow: none; + background-color: transparent; + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNiIgd2lkdGg9IjEwIj48cG9seWdvbiBwb2ludHM9IjAsMCAxMCwwIDUsNiIgc3R5bGU9ImZpbGw6cmdiYSgwLDAsMCwuMjQpOyIvPjwvc3ZnPg=="); + background-repeat: no-repeat; + background-position: right center; + cursor: pointer; + color: rgba(0, 0, 0, 0.87); + font-size: 16px; + padding: 0 25px 0 0; } + .mui-select > select::-ms-expand { + display: none; } + .mui-select > select:focus { + outline: 0; + height: 33px; + margin-bottom: -1px; + border-color: #2196F3; + border-width: 2px; } + .mui-select > select:disabled { + color: rgba(0, 0, 0, 0.38); + cursor: not-allowed; + background-color: transparent; + opacity: 1; } + +.mui-select__menu { + position: absolute; + z-index: 1; + min-width: 100%; + overflow-y: auto; + padding: 8px 0; + background-color: #FFF; + font-size: 16px; } + @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + .mui-select__menu { + border-left: 1px solid rgba(0, 0, 0, 0.12); + border-top: 1px solid rgba(0, 0, 0, 0.12); } } + .mui-select__menu > div { + padding: 0 22px; + height: 42px; + line-height: 42px; + cursor: pointer; + white-space: nowrap; } + .mui-select__menu > div:hover { + background-color: #E0E0E0; } + .mui-select__menu > div.mui--is-selected { + background-color: #EEEEEE; } + +/** + * MUI Table Component + */ +th { + text-align: left; } + +.mui-table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; } + .mui-table > thead > tr > th, + .mui-table > thead > tr > td, + .mui-table > tbody > tr > th, + .mui-table > tbody > tr > td, + .mui-table > tfoot > tr > th, + .mui-table > tfoot > tr > td { + padding: 10px; + line-height: 1.429; } + .mui-table > thead > tr > th { + border-bottom: 2px solid rgba(0, 0, 0, 0.12); + font-weight: 700; } + .mui-table > tbody + tbody { + border-top: 2px solid rgba(0, 0, 0, 0.12); } + .mui-table.mui-table--bordered > tbody > tr > td { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); } + +/** + * MUI Tabs module + */ +.mui-tabs__bar { + list-style: none; + padding-left: 0; + margin-bottom: 0; + background-color: transparent; + white-space: nowrap; + overflow-x: auto; } + .mui-tabs__bar > li { + display: inline-block; } + .mui-tabs__bar > li > a { + display: block; + white-space: nowrap; + text-transform: uppercase; + font-weight: 500; + font-size: 14px; + color: rgba(0, 0, 0, 0.87); + cursor: default; + height: 48px; + line-height: 48px; + padding-left: 24px; + padding-right: 24px; + user-select: none; } + .mui-tabs__bar > li > a:hover { + text-decoration: none; } + .mui-tabs__bar > li.mui--is-active { + border-bottom: 2px solid #2196F3; } + .mui-tabs__bar > li.mui--is-active > a { + color: #2196F3; } + .mui-tabs__bar.mui-tabs__bar--justified { + display: table; + width: 100%; + table-layout: fixed; } + .mui-tabs__bar.mui-tabs__bar--justified > li { + display: table-cell; } + .mui-tabs__bar.mui-tabs__bar--justified > li > a { + text-align: center; + padding-left: 0px; + padding-right: 0px; } + +.mui-tabs__pane { + display: none; } + .mui-tabs__pane.mui--is-active { + display: block; } + +[data-mui-toggle="tab"] { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; } + +/** + * MUI Textfield Component + */ +.mui-textfield { + display: block; + padding-top: 15px; + margin-bottom: 20px; + position: relative; } + .mui-textfield > label { + position: absolute; + top: 0; + display: block; + width: 100%; + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + font-weight: 400; + line-height: 15px; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .mui-textfield > textarea { + padding-top: 5px; } + .mui-textfield > input, + .mui-textfield > textarea { + display: block; } + .mui-textfield > input:focus ~ label, + .mui-textfield > textarea:focus ~ label { + color: #2196F3; } + +.mui-textfield--float-label > label { + position: absolute; + transform: translate(0px, 15px); + font-size: 16px; + line-height: 32px; + color: rgba(0, 0, 0, 0.26); + text-overflow: clip; + cursor: text; + pointer-events: none; } + +.mui-textfield--float-label > input:focus ~ label, +.mui-textfield--float-label > textarea:focus ~ label { + transform: translate(0px, 0px); + font-size: 12px; + line-height: 15px; + text-overflow: ellipsis; } + +.mui-textfield--float-label > input:not(:focus).mui--is-not-empty ~ label, .mui-textfield--float-label > input:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, .mui-textfield--float-label > input:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield--float-label > textarea:not(:focus).mui--is-not-empty ~ label, +.mui-textfield--float-label > textarea:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield--float-label > textarea:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label { + color: rgba(0, 0, 0, 0.54); + font-size: 12px; + line-height: 15px; + transform: translate(0px, 0px); + text-overflow: ellipsis; } + +.mui-textfield--wrap-label { + display: table; + width: 100%; + padding-top: 0px; } + .mui-textfield--wrap-label:not(.mui-textfield--float-label) > label { + display: table-header-group; + position: static; + white-space: normal; + overflow-x: visible; } + +.mui-textfield > input, +.mui-textfield > textarea { + animation-duration: 0.0001s; + animation-name: mui-node-inserted; + display: block; + background-color: transparent; + color: rgba(0, 0, 0, 0.87); + border: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.26); + outline: none; + width: 100%; + font-size: 16px; + padding: 0; + box-shadow: none; + border-radius: 0px; + background-image: none; } + .mui-textfield > input:focus, + .mui-textfield > textarea:focus { + border-color: #2196F3; + border-width: 2px; } + .mui-textfield > input:disabled, .mui-textfield > input:read-only, + .mui-textfield > textarea:disabled, + .mui-textfield > textarea:read-only { + cursor: not-allowed; + background-color: transparent; + opacity: 1; } + .mui-textfield > input::placeholder, + .mui-textfield > textarea::placeholder { + color: rgba(0, 0, 0, 0.26); + opacity: 1; } + +.mui-textfield > input { + height: 32px; } + .mui-textfield > input:focus { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > textarea { + min-height: 64px; } + .mui-textfield > textarea[rows]:not([rows="2"]):focus { + margin-bottom: -1px; } + +.mui-textfield > input:focus { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > input:invalid:not(:focus):not(:required), .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty, .mui-textfield > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:invalid:not(:focus):not(:required), +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-not-empty, +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, +.mui-textfield > textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) { + border-color: #F44336; + border-width: 2px; } + +.mui-textfield > input:invalid:not(:focus):not(:required), .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty, .mui-textfield > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required), +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty), +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) { + height: 33px; + margin-bottom: -1px; } + +.mui-textfield > input:invalid:not(:focus):not(:required) ~ label, .mui-textfield > input:invalid:not(:focus):required.mui--is-not-empty ~ label, .mui-textfield > input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, .mui-textfield > input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:invalid:not(:focus):not(:required) ~ label, +.mui-textfield > textarea:invalid:not(:focus):required.mui--is-not-empty ~ label, +.mui-textfield > textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:not(:required) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required.mui--is-not-empty ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:not(:required) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty) ~ label, +.mui-textfield > textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty) ~ label { + color: #F44336; } + +.mui-textfield:not(.mui-textfield--float-label) > input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty ~ label, +.mui-textfield:not(.mui-textfield--float-label) > textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty ~ label { + color: #F44336; } + +/** + * MUI Helpers module + */ +@keyframes mui-node-inserted { + from { + opacity: 0.99; } + to { + opacity: 1; } } + +.mui--no-transition { + transition: none !important; } + +.mui--no-user-select { + user-select: none; } + +.mui-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; } + +.mui--text-left { + text-align: left !important; } + +.mui--text-right { + text-align: right !important; } + +.mui--text-center { + text-align: center !important; } + +.mui--text-justify { + text-align: justify !important; } + +.mui--text-nowrap { + white-space: nowrap !important; } + +.mui--align-baseline { + vertical-align: baseline !important; } + +.mui--align-top { + vertical-align: top !important; } + +.mui--align-middle { + vertical-align: middle !important; } + +.mui--align-bottom { + vertical-align: bottom !important; } + +.mui--text-dark { + color: rgba(0, 0, 0, 0.87); } + +.mui--text-dark-secondary { + color: rgba(0, 0, 0, 0.54); } + +.mui--text-dark-hint { + color: rgba(0, 0, 0, 0.38); } + +.mui--text-light { + color: #FFF; } + +.mui--text-light-secondary { + color: rgba(255, 255, 255, 0.7); } + +.mui--text-light-hint { + color: rgba(255, 255, 255, 0.3); } + +.mui--text-accent { + color: rgba(186, 214, 73, 0.87); } + +.mui--text-accent-secondary { + color: rgba(186, 214, 73, 0.54); } + +.mui--text-accent-hint { + color: rgba(186, 214, 73, 0.38); } + +.mui--text-black { + color: #000; } + +.mui--text-white { + color: #FFF; } + +.mui--text-danger { + color: #F44336; } + +.mui-list--unstyled { + padding-left: 0; + list-style: none; } + +.mui-list--inline { + padding-left: 0; + list-style: none; + margin-left: -5px; } + .mui-list--inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; } + +.mui--z1, .mui-dropdown__menu, .mui-select__menu { + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); } + +.mui--z2 { + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); } + +.mui--z3 { + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); } + +.mui--z4 { + box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22); } + +.mui--z5 { + box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22); } + +.mui--clearfix:before, .mui--clearfix:after { + content: " "; + display: table; } + +.mui--clearfix:after { + clear: both; } + +.mui--pull-right { + float: right !important; } + +.mui--pull-left { + float: left !important; } + +.mui--hide { + display: none !important; } + +.mui--show { + display: block !important; } + +.mui--invisible { + visibility: hidden; } + +.mui--overflow-hidden { + overflow: hidden !important; } + +.mui--overflow-hidden-x { + overflow-x: hidden !important; } + +.mui--overflow-hidden-y { + overflow-y: hidden !important; } + +.mui--visible-xs-block, +.mui--visible-xs-inline, +.mui--visible-xs-inline-block, +.mui--visible-sm-block, +.mui--visible-sm-inline, +.mui--visible-sm-inline-block, +.mui--visible-md-block, +.mui--visible-md-inline, +.mui--visible-md-inline-block, +.mui--visible-lg-block, +.mui--visible-lg-inline, +.mui--visible-lg-inline-block, +.mui--visible-xl-block, +.mui--visible-xl-inline, +.mui--visible-xl-inline-block { + display: none !important; } + +@media (max-width: 543px) { + .mui-visible-xs { + display: block !important; } + table.mui-visible-xs { + display: table; } + tr.mui-visible-xs { + display: table-row !important; } + th.mui-visible-xs, + td.mui-visible-xs { + display: table-cell !important; } + .mui--visible-xs-block { + display: block !important; } + .mui--visible-xs-inline { + display: inline !important; } + .mui--visible-xs-inline-block { + display: inline-block !important; } } + +@media (min-width: 544px) and (max-width: 767px) { + .mui-visible-sm { + display: block !important; } + table.mui-visible-sm { + display: table; } + tr.mui-visible-sm { + display: table-row !important; } + th.mui-visible-sm, + td.mui-visible-sm { + display: table-cell !important; } + .mui--visible-sm-block { + display: block !important; } + .mui--visible-sm-inline { + display: inline !important; } + .mui--visible-sm-inline-block { + display: inline-block !important; } } + +@media (min-width: 768px) and (max-width: 991px) { + .mui-visible-md { + display: block !important; } + table.mui-visible-md { + display: table; } + tr.mui-visible-md { + display: table-row !important; } + th.mui-visible-md, + td.mui-visible-md { + display: table-cell !important; } + .mui--visible-md-block { + display: block !important; } + .mui--visible-md-inline { + display: inline !important; } + .mui--visible-md-inline-block { + display: inline-block !important; } } + +@media (min-width: 992px) and (max-width: 1199px) { + .mui-visible-lg { + display: block !important; } + table.mui-visible-lg { + display: table; } + tr.mui-visible-lg { + display: table-row !important; } + th.mui-visible-lg, + td.mui-visible-lg { + display: table-cell !important; } + .mui--visible-lg-block { + display: block !important; } + .mui--visible-lg-inline { + display: inline !important; } + .mui--visible-lg-inline-block { + display: inline-block !important; } } + +@media (min-width: 1200px) { + .mui-visible-xl { + display: block !important; } + table.mui-visible-xl { + display: table; } + tr.mui-visible-xl { + display: table-row !important; } + th.mui-visible-xl, + td.mui-visible-xl { + display: table-cell !important; } + .mui--visible-xl-block { + display: block !important; } + .mui--visible-xl-inline { + display: inline !important; } + .mui--visible-xl-inline-block { + display: inline-block !important; } } + +@media (max-width: 543px) { + .mui--hidden-xs { + display: none !important; } } + +@media (min-width: 544px) and (max-width: 767px) { + .mui--hidden-sm { + display: none !important; } } + +@media (min-width: 768px) and (max-width: 991px) { + .mui--hidden-md { + display: none !important; } } + +@media (min-width: 992px) and (max-width: 1199px) { + .mui--hidden-lg { + display: none !important; } } + +@media (min-width: 1200px) { + .mui--hidden-xl { + display: none !important; } } + +body.mui-body--scroll-lock { + overflow: hidden !important; } + +/** + * MUI Overlay module + */ +#mui-overlay { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 99999999; + background-color: rgba(0, 0, 0, 0.2); + overflow: auto; } + +/** + * MUI Ripple module + */ +.mui-ripple-effect { + position: absolute; + border-radius: 50%; + pointer-events: none; + opacity: 0; + animation: mui-ripple-animation 2s; } + +@keyframes mui-ripple-animation { + from { + transform: scale(1); + opacity: 0.4; } + to { + transform: scale(100); + opacity: 0; } } + +.mui-btn > .mui-ripple-effect { + background-color: #a6a6a6; } + +.mui-btn--primary > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--dark > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--danger > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--accent > .mui-ripple-effect { + background-color: #FFF; } + +.mui-btn--flat > .mui-ripple-effect { + background-color: #a6a6a6; } + +/** + * MUI Typography module + */ +.mui--text-display4 { + font-weight: 300; + font-size: 112px; + line-height: 112px; } + +.mui--text-display3 { + font-weight: 400; + font-size: 56px; + line-height: 56px; } + +.mui--text-display2 { + font-weight: 400; + font-size: 45px; + line-height: 48px; } + +.mui--text-display1, h1 { + font-weight: 400; + font-size: 34px; + line-height: 40px; } + +.mui--text-headline, h2 { + font-weight: 400; + font-size: 24px; + line-height: 32px; } + +.mui--text-title, h3 { + font-weight: 400; + font-size: 20px; + line-height: 28px; } + +.mui--text-subhead, h4 { + font-weight: 400; + font-size: 16px; + line-height: 24px; } + +.mui--text-body2, h5 { + font-weight: 500; + font-size: 14px; + line-height: 24px; } + +.mui--text-body1 { + font-weight: 400; + font-size: 14px; + line-height: 20px; } + +.mui--text-caption { + font-weight: 400; + font-size: 12px; + line-height: 16px; } + +.mui--text-menu { + font-weight: 500; + font-size: 13px; + line-height: 17px; } + +.mui--text-button { + font-weight: 500; + font-size: 14px; + line-height: 18px; + text-transform: uppercase; } + diff --git a/mdot/mdot_server/mdot_server/app/css/mui.min.css b/mdot/mdot_server/mdot_server/app/css/mui.min.css new file mode 100644 index 0000000..5ea8f9e --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/mui.min.css @@ -0,0 +1 @@ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */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:700}dfn{font-style:italic}h1{font-size:2em;margin:.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:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{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]{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;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{box-sizing:border-box}:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:Arial,Verdana,Tahoma;font-size:14px;font-weight:400;line-height:1.429;color:rgba(0,0,0,.87);background-color:#FFF}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#2196F3;text-decoration:none}a:focus,a:hover{color:#1976D2;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}p{margin:0 0 10px}ol,ul{margin-top:0;margin-bottom:10px}figure{margin:0}img{vertical-align:middle}hr{margin-top:20px;margin-bottom:20px;border:0;height:1px;background-color:rgba(0,0,0,.12)}legend{display:block;width:100%;padding:0;margin-bottom:10px;font-size:21px;color:rgba(0,0,0,.87);line-height:inherit;border:0}input[type=search]{box-sizing:border-box;-webkit-appearance:none}input[type=checkbox]:focus,input[type=radio]:focus,input[type=file]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}strong{font-weight:700}abbr[title]{cursor:help;border-bottom:1px dotted #2196F3}h1,h2,h3{margin-top:20px;margin-bottom:10px}h4,h5,h6{margin-top:10px;margin-bottom:10px}.mui--appbar-height{height:56px}.mui--appbar-min-height,.mui-appbar{min-height:56px}.mui--appbar-line-height{line-height:56px}.mui--appbar-top{top:56px}@media (orientation:landscape) and (max-height:480px){.mui--appbar-height{height:48px}.mui--appbar-min-height,.mui-appbar{min-height:48px}.mui--appbar-line-height{line-height:48px}.mui--appbar-top{top:48px}}@media (min-width:480px){.mui--appbar-height{height:64px}.mui--appbar-min-height,.mui-appbar{min-height:64px}.mui--appbar-line-height{line-height:64px}.mui--appbar-top{top:64px}}.mui-appbar{background-color:#2196F3;color:#FFF}.mui-btn{-webkit-animation-duration:.1ms;animation-duration:.1ms;-webkit-animation-name:mui-node-inserted;animation-name:mui-node-inserted;font-weight:500;font-size:14px;line-height:18px;text-transform:uppercase;color:rgba(0,0,0,.87);background-color:#FFF;transition:all .2s ease-in-out;display:inline-block;height:36px;padding:0 26px;margin-top:6px;margin-bottom:6px;border:none;border-radius:2px;cursor:pointer;-ms-touch-action:manipulation;touch-action:manipulation;background-image:none;text-align:center;line-height:36px;vertical-align:middle;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px;letter-spacing:.03em;position:relative;overflow:hidden}.mui-btn:active,.mui-btn:focus,.mui-btn:hover{color:rgba(0,0,0,.87);background-color:#fff}.mui-btn[disabled]:active,.mui-btn[disabled]:focus,.mui-btn[disabled]:hover{color:rgba(0,0,0,.87);background-color:#FFF}.mui-btn.mui-btn--flat{color:rgba(0,0,0,.87);background-color:transparent}.mui-btn.mui-btn--flat:active,.mui-btn.mui-btn--flat:focus,.mui-btn.mui-btn--flat:hover{color:rgba(0,0,0,.87);background-color:#f2f2f2}.mui-btn.mui-btn--flat[disabled]:active,.mui-btn.mui-btn--flat[disabled]:focus,.mui-btn.mui-btn--flat[disabled]:hover{color:rgba(0,0,0,.87);background-color:transparent}.mui-btn:active,.mui-btn:focus,.mui-btn:hover{outline:0;text-decoration:none;color:rgba(0,0,0,.87)}.mui-btn:focus,.mui-btn:hover{box-shadow:0 0 2px rgba(0,0,0,.12),0 2px 2px rgba(0,0,0,.2)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-btn:focus,.mui-btn:hover{box-shadow:0 -1px 2px rgba(0,0,0,.12),-1px 0 2px rgba(0,0,0,.12),0 0 2px rgba(0,0,0,.12),0 2px 2px rgba(0,0,0,.2)}}.mui-btn:active{box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-btn:active{box-shadow:0 -1px 2px rgba(0,0,0,.12),-1px 0 2px rgba(0,0,0,.12),0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}}.mui-btn.mui--is-disabled,.mui-btn:disabled{cursor:not-allowed;pointer-events:none;opacity:.6;box-shadow:none}.mui-btn+.mui-btn{margin-left:8px}.mui-btn--flat{background-color:transparent}.mui-btn--flat:active,.mui-btn--flat:focus,.mui-btn--flat:hover{box-shadow:none;background-color:#f2f2f2}.mui-btn--fab,.mui-btn--raised{box-shadow:0 0 2px rgba(0,0,0,.12),0 2px 2px rgba(0,0,0,.2)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-btn--fab,.mui-btn--raised{box-shadow:0 -1px 2px rgba(0,0,0,.12),-1px 0 2px rgba(0,0,0,.12),0 0 2px rgba(0,0,0,.12),0 2px 2px rgba(0,0,0,.2)}}.mui-btn--fab:active,.mui-btn--raised:active{box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-btn--fab:active,.mui-btn--raised:active{box-shadow:0 -1px 2px rgba(0,0,0,.12),-1px 0 2px rgba(0,0,0,.12),0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}}.mui-btn--fab{position:relative;padding:0;width:55px;height:55px;line-height:55px;border-radius:50%;z-index:1}.mui-btn--primary{color:#FFF;background-color:#2196F3}.mui-btn--primary:active,.mui-btn--primary:focus,.mui-btn--primary:hover{color:#FFF;background-color:#39a1f4}.mui-btn--primary[disabled]:active,.mui-btn--primary[disabled]:focus,.mui-btn--primary[disabled]:hover{color:#FFF;background-color:#2196F3}.mui-btn--primary.mui-btn--flat{color:#2196F3;background-color:transparent}.mui-btn--primary.mui-btn--flat:active,.mui-btn--primary.mui-btn--flat:focus,.mui-btn--primary.mui-btn--flat:hover{color:#2196F3;background-color:#f2f2f2}.mui-btn--primary.mui-btn--flat[disabled]:active,.mui-btn--primary.mui-btn--flat[disabled]:focus,.mui-btn--primary.mui-btn--flat[disabled]:hover{color:#2196F3;background-color:transparent}.mui-btn--dark{color:#FFF;background-color:#424242}.mui-btn--dark:active,.mui-btn--dark:focus,.mui-btn--dark:hover{color:#FFF;background-color:#4f4f4f}.mui-btn--dark[disabled]:active,.mui-btn--dark[disabled]:focus,.mui-btn--dark[disabled]:hover{color:#FFF;background-color:#424242}.mui-btn--dark.mui-btn--flat{color:#424242;background-color:transparent}.mui-btn--dark.mui-btn--flat:active,.mui-btn--dark.mui-btn--flat:focus,.mui-btn--dark.mui-btn--flat:hover{color:#424242;background-color:#f2f2f2}.mui-btn--dark.mui-btn--flat[disabled]:active,.mui-btn--dark.mui-btn--flat[disabled]:focus,.mui-btn--dark.mui-btn--flat[disabled]:hover{color:#424242;background-color:transparent}.mui-btn--danger{color:#FFF;background-color:#F44336}.mui-btn--danger:active,.mui-btn--danger:focus,.mui-btn--danger:hover{color:#FFF;background-color:#f55a4e}.mui-btn--danger[disabled]:active,.mui-btn--danger[disabled]:focus,.mui-btn--danger[disabled]:hover{color:#FFF;background-color:#F44336}.mui-btn--danger.mui-btn--flat{color:#F44336;background-color:transparent}.mui-btn--danger.mui-btn--flat:active,.mui-btn--danger.mui-btn--flat:focus,.mui-btn--danger.mui-btn--flat:hover{color:#F44336;background-color:#f2f2f2}.mui-btn--danger.mui-btn--flat[disabled]:active,.mui-btn--danger.mui-btn--flat[disabled]:focus,.mui-btn--danger.mui-btn--flat[disabled]:hover{color:#F44336;background-color:transparent}.mui-btn--accent{color:#FFF;background-color:#FF4081}.mui-btn--accent:active,.mui-btn--accent:focus,.mui-btn--accent:hover{color:#FFF;background-color:#ff5a92}.mui-btn--accent[disabled]:active,.mui-btn--accent[disabled]:focus,.mui-btn--accent[disabled]:hover{color:#FFF;background-color:#FF4081}.mui-btn--accent.mui-btn--flat{color:#FF4081;background-color:transparent}.mui-btn--accent.mui-btn--flat:active,.mui-btn--accent.mui-btn--flat:focus,.mui-btn--accent.mui-btn--flat:hover{color:#FF4081;background-color:#f2f2f2}.mui-btn--accent.mui-btn--flat[disabled]:active,.mui-btn--accent.mui-btn--flat[disabled]:focus,.mui-btn--accent.mui-btn--flat[disabled]:hover{color:#FF4081;background-color:transparent}.mui-btn--small{height:30.6px;line-height:30.6px;padding:0 16px;font-size:13px}.mui-btn--large{height:54px;line-height:54px;padding:0 26px;font-size:14px}.mui-btn--fab.mui-btn--small{width:44px;height:44px;line-height:44px}.mui-btn--fab.mui-btn--large{width:75px;height:75px;line-height:75px}.mui-checkbox,.mui-radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.mui-checkbox>label,.mui-radio>label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.mui-checkbox--inline>label>input[type=checkbox],.mui-checkbox>label>input[type=checkbox],.mui-radio--inline>label>input[type=radio],.mui-radio>label>input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px}.mui-checkbox+.mui-checkbox,.mui-radio+.mui-radio{margin-top:-5px}.mui-checkbox--inline,.mui-radio--inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.mui-checkbox--inline>input[type=checkbox],.mui-checkbox--inline>input[type=radio],.mui-checkbox--inline>label>input[type=checkbox],.mui-checkbox--inline>label>input[type=radio],.mui-radio--inline>input[type=checkbox],.mui-radio--inline>input[type=radio],.mui-radio--inline>label>input[type=checkbox],.mui-radio--inline>label>input[type=radio]{margin:4px 0 0;line-height:normal}.mui-checkbox--inline+.mui-checkbox--inline,.mui-radio--inline+.mui-radio--inline{margin-top:0;margin-left:10px}.mui-container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.mui-container:after,.mui-container:before{content:" ";display:table}.mui-container:after{clear:both}@media (min-width:544px){.mui-container{max-width:570px}}@media (min-width:768px){.mui-container{max-width:740px}}@media (min-width:992px){.mui-container{max-width:960px}}@media (min-width:1200px){.mui-container{max-width:1170px}}.mui-container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.mui-container-fluid:after,.mui-container-fluid:before{content:" ";display:table}.mui-container-fluid:after{clear:both}.mui-divider{display:block;height:1px;background-color:rgba(0,0,0,.12)}.mui--divider-top{border-top:1px solid rgba(0,0,0,.12)}.mui--divider-bottom{border-bottom:1px solid rgba(0,0,0,.12)}.mui--divider-left{border-left:1px solid rgba(0,0,0,.12)}.mui--divider-right{border-right:1px solid rgba(0,0,0,.12)}.mui-dropdown{display:inline-block;position:relative}[data-mui-toggle=dropdown]{-webkit-animation-duration:.1ms;animation-duration:.1ms;-webkit-animation-name:mui-node-inserted;animation-name:mui-node-inserted;outline:0}.mui-dropdown__menu{position:absolute;top:100%;left:0;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#FFF;border-radius:2px;z-index:1;background-clip:padding-box}.mui-dropdown__menu.mui--is-open{display:block}.mui-dropdown__menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.429;color:rgba(0,0,0,.87);white-space:nowrap}.mui-dropdown__menu>li>a:focus,.mui-dropdown__menu>li>a:hover{text-decoration:none;color:rgba(0,0,0,.87);background-color:#EEE}.mui-dropdown__menu>.mui--is-disabled>a,.mui-dropdown__menu>.mui--is-disabled>a:focus,.mui-dropdown__menu>.mui--is-disabled>a:hover{color:#EEE}.mui-dropdown__menu>.mui--is-disabled>a:focus,.mui-dropdown__menu>.mui--is-disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;cursor:not-allowed}.mui-dropdown__menu--right{left:auto;right:0}@media (min-width:544px){.mui-form--inline>.mui-textfield{display:inline-block;margin-bottom:0}.mui-form--inline>.mui-checkbox,.mui-form--inline>.mui-radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.mui-form--inline>.mui-checkbox>label,.mui-form--inline>.mui-radio>label{padding-left:0}.mui-form--inline>.mui-checkbox>label>input[type=checkbox],.mui-form--inline>.mui-radio>label>input[type=radio]{position:relative;margin-left:0}.mui-form--inline>.mui-select{display:inline-block}.mui-form--inline>.mui-btn{margin-bottom:0;margin-top:0;vertical-align:bottom}}.mui-row{margin-left:-15px;margin-right:-15px}.mui-row:after,.mui-row:before{content:" ";display:table}.mui-row:after{clear:both}.mui-col-lg-1,.mui-col-lg-10,.mui-col-lg-11,.mui-col-lg-12,.mui-col-lg-2,.mui-col-lg-3,.mui-col-lg-4,.mui-col-lg-5,.mui-col-lg-6,.mui-col-lg-7,.mui-col-lg-8,.mui-col-lg-9,.mui-col-md-1,.mui-col-md-10,.mui-col-md-11,.mui-col-md-12,.mui-col-md-2,.mui-col-md-3,.mui-col-md-4,.mui-col-md-5,.mui-col-md-6,.mui-col-md-7,.mui-col-md-8,.mui-col-md-9,.mui-col-sm-1,.mui-col-sm-10,.mui-col-sm-11,.mui-col-sm-12,.mui-col-sm-2,.mui-col-sm-3,.mui-col-sm-4,.mui-col-sm-5,.mui-col-sm-6,.mui-col-sm-7,.mui-col-sm-8,.mui-col-sm-9,.mui-col-xs-1,.mui-col-xs-10,.mui-col-xs-11,.mui-col-xs-12,.mui-col-xs-2,.mui-col-xs-3,.mui-col-xs-4,.mui-col-xs-5,.mui-col-xs-6,.mui-col-xs-7,.mui-col-xs-8,.mui-col-xs-9{min-height:1px;padding-left:15px;padding-right:15px}.mui-col-xs-1,.mui-col-xs-10,.mui-col-xs-11,.mui-col-xs-12,.mui-col-xs-2,.mui-col-xs-3,.mui-col-xs-4,.mui-col-xs-5,.mui-col-xs-6,.mui-col-xs-7,.mui-col-xs-8,.mui-col-xs-9{float:left}.mui-col-xs-1{width:8.33333%}.mui-col-xs-2{width:16.66667%}.mui-col-xs-3{width:25%}.mui-col-xs-4{width:33.33333%}.mui-col-xs-5{width:41.66667%}.mui-col-xs-6{width:50%}.mui-col-xs-7{width:58.33333%}.mui-col-xs-8{width:66.66667%}.mui-col-xs-9{width:75%}.mui-col-xs-10{width:83.33333%}.mui-col-xs-11{width:91.66667%}.mui-col-xs-12{width:100%}.mui-col-xs-offset-0{margin-left:0}.mui-col-xs-offset-1{margin-left:8.33333%}.mui-col-xs-offset-2{margin-left:16.66667%}.mui-col-xs-offset-3{margin-left:25%}.mui-col-xs-offset-4{margin-left:33.33333%}.mui-col-xs-offset-5{margin-left:41.66667%}.mui-col-xs-offset-6{margin-left:50%}.mui-col-xs-offset-7{margin-left:58.33333%}.mui-col-xs-offset-8{margin-left:66.66667%}.mui-col-xs-offset-9{margin-left:75%}.mui-col-xs-offset-10{margin-left:83.33333%}.mui-col-xs-offset-11{margin-left:91.66667%}.mui-col-xs-offset-12{margin-left:100%}@media (min-width:544px){.mui-col-sm-1,.mui-col-sm-10,.mui-col-sm-11,.mui-col-sm-12,.mui-col-sm-2,.mui-col-sm-3,.mui-col-sm-4,.mui-col-sm-5,.mui-col-sm-6,.mui-col-sm-7,.mui-col-sm-8,.mui-col-sm-9{float:left}.mui-col-sm-1{width:8.33333%}.mui-col-sm-2{width:16.66667%}.mui-col-sm-3{width:25%}.mui-col-sm-4{width:33.33333%}.mui-col-sm-5{width:41.66667%}.mui-col-sm-6{width:50%}.mui-col-sm-7{width:58.33333%}.mui-col-sm-8{width:66.66667%}.mui-col-sm-9{width:75%}.mui-col-sm-10{width:83.33333%}.mui-col-sm-11{width:91.66667%}.mui-col-sm-12{width:100%}.mui-col-sm-offset-0{margin-left:0}.mui-col-sm-offset-1{margin-left:8.33333%}.mui-col-sm-offset-2{margin-left:16.66667%}.mui-col-sm-offset-3{margin-left:25%}.mui-col-sm-offset-4{margin-left:33.33333%}.mui-col-sm-offset-5{margin-left:41.66667%}.mui-col-sm-offset-6{margin-left:50%}.mui-col-sm-offset-7{margin-left:58.33333%}.mui-col-sm-offset-8{margin-left:66.66667%}.mui-col-sm-offset-9{margin-left:75%}.mui-col-sm-offset-10{margin-left:83.33333%}.mui-col-sm-offset-11{margin-left:91.66667%}.mui-col-sm-offset-12{margin-left:100%}}@media (min-width:768px){.mui-col-md-1,.mui-col-md-10,.mui-col-md-11,.mui-col-md-12,.mui-col-md-2,.mui-col-md-3,.mui-col-md-4,.mui-col-md-5,.mui-col-md-6,.mui-col-md-7,.mui-col-md-8,.mui-col-md-9{float:left}.mui-col-md-1{width:8.33333%}.mui-col-md-2{width:16.66667%}.mui-col-md-3{width:25%}.mui-col-md-4{width:33.33333%}.mui-col-md-5{width:41.66667%}.mui-col-md-6{width:50%}.mui-col-md-7{width:58.33333%}.mui-col-md-8{width:66.66667%}.mui-col-md-9{width:75%}.mui-col-md-10{width:83.33333%}.mui-col-md-11{width:91.66667%}.mui-col-md-12{width:100%}.mui-col-md-offset-0{margin-left:0}.mui-col-md-offset-1{margin-left:8.33333%}.mui-col-md-offset-2{margin-left:16.66667%}.mui-col-md-offset-3{margin-left:25%}.mui-col-md-offset-4{margin-left:33.33333%}.mui-col-md-offset-5{margin-left:41.66667%}.mui-col-md-offset-6{margin-left:50%}.mui-col-md-offset-7{margin-left:58.33333%}.mui-col-md-offset-8{margin-left:66.66667%}.mui-col-md-offset-9{margin-left:75%}.mui-col-md-offset-10{margin-left:83.33333%}.mui-col-md-offset-11{margin-left:91.66667%}.mui-col-md-offset-12{margin-left:100%}}@media (min-width:992px){.mui-col-lg-1,.mui-col-lg-10,.mui-col-lg-11,.mui-col-lg-12,.mui-col-lg-2,.mui-col-lg-3,.mui-col-lg-4,.mui-col-lg-5,.mui-col-lg-6,.mui-col-lg-7,.mui-col-lg-8,.mui-col-lg-9{float:left}.mui-col-lg-1{width:8.33333%}.mui-col-lg-2{width:16.66667%}.mui-col-lg-3{width:25%}.mui-col-lg-4{width:33.33333%}.mui-col-lg-5{width:41.66667%}.mui-col-lg-6{width:50%}.mui-col-lg-7{width:58.33333%}.mui-col-lg-8{width:66.66667%}.mui-col-lg-9{width:75%}.mui-col-lg-10{width:83.33333%}.mui-col-lg-11{width:91.66667%}.mui-col-lg-12{width:100%}.mui-col-lg-offset-0{margin-left:0}.mui-col-lg-offset-1{margin-left:8.33333%}.mui-col-lg-offset-2{margin-left:16.66667%}.mui-col-lg-offset-3{margin-left:25%}.mui-col-lg-offset-4{margin-left:33.33333%}.mui-col-lg-offset-5{margin-left:41.66667%}.mui-col-lg-offset-6{margin-left:50%}.mui-col-lg-offset-7{margin-left:58.33333%}.mui-col-lg-offset-8{margin-left:66.66667%}.mui-col-lg-offset-9{margin-left:75%}.mui-col-lg-offset-10{margin-left:83.33333%}.mui-col-lg-offset-11{margin-left:91.66667%}.mui-col-lg-offset-12{margin-left:100%}}@media (min-width:1200px){.mui-col-xl-1,.mui-col-xl-10,.mui-col-xl-11,.mui-col-xl-12,.mui-col-xl-2,.mui-col-xl-3,.mui-col-xl-4,.mui-col-xl-5,.mui-col-xl-6,.mui-col-xl-7,.mui-col-xl-8,.mui-col-xl-9{float:left}.mui-col-xl-1{width:8.33333%}.mui-col-xl-2{width:16.66667%}.mui-col-xl-3{width:25%}.mui-col-xl-4{width:33.33333%}.mui-col-xl-5{width:41.66667%}.mui-col-xl-6{width:50%}.mui-col-xl-7{width:58.33333%}.mui-col-xl-8{width:66.66667%}.mui-col-xl-9{width:75%}.mui-col-xl-10{width:83.33333%}.mui-col-xl-11{width:91.66667%}.mui-col-xl-12{width:100%}.mui-col-xl-offset-0{margin-left:0}.mui-col-xl-offset-1{margin-left:8.33333%}.mui-col-xl-offset-2{margin-left:16.66667%}.mui-col-xl-offset-3{margin-left:25%}.mui-col-xl-offset-4{margin-left:33.33333%}.mui-col-xl-offset-5{margin-left:41.66667%}.mui-col-xl-offset-6{margin-left:50%}.mui-col-xl-offset-7{margin-left:58.33333%}.mui-col-xl-offset-8{margin-left:66.66667%}.mui-col-xl-offset-9{margin-left:75%}.mui-col-xl-offset-10{margin-left:83.33333%}.mui-col-xl-offset-11{margin-left:91.66667%}.mui-col-xl-offset-12{margin-left:100%}}.mui-panel{padding:15px;margin-bottom:20px;border-radius:0;background-color:#FFF;box-shadow:0 2px 2px 0 rgba(0,0,0,.16),0 0 2px 0 rgba(0,0,0,.12)}.mui-panel:after,.mui-panel:before{content:" ";display:table}.mui-panel:after{clear:both}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-panel{box-shadow:0 -1px 2px 0 rgba(0,0,0,.12),-1px 0 2px 0 rgba(0,0,0,.12),0 2px 2px 0 rgba(0,0,0,.16),0 0 2px 0 rgba(0,0,0,.12)}}.mui-select{display:block;padding-top:15px;margin-bottom:20px;position:relative}.mui-select:focus{outline:0}.mui-select:focus>select{height:33px;margin-bottom:-1px;border-color:#2196F3;border-width:2px}.mui-select>select{-webkit-animation-duration:.1ms;animation-duration:.1ms;-webkit-animation-name:mui-node-inserted;animation-name:mui-node-inserted;display:block;height:32px;width:100%;appearance:none;-webkit-appearance:none;-moz-appearance:none;outline:0;border:none;border-bottom:1px solid rgba(0,0,0,.26);border-radius:0;box-shadow:none;background-color:transparent;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iNiIgd2lkdGg9IjEwIj48cG9seWdvbiBwb2ludHM9IjAsMCAxMCwwIDUsNiIgc3R5bGU9ImZpbGw6cmdiYSgwLDAsMCwuMjQpOyIvPjwvc3ZnPg==);background-repeat:no-repeat;background-position:right center;cursor:pointer;color:rgba(0,0,0,.87);font-size:16px;padding:0 25px 0 0}.mui-select>select::-ms-expand{display:none}.mui-select>select:focus{outline:0;height:33px;margin-bottom:-1px;border-color:#2196F3;border-width:2px}.mui-select>select:disabled{color:rgba(0,0,0,.38);cursor:not-allowed;background-color:transparent;opacity:1}.mui-select__menu{position:absolute;z-index:1;min-width:100%;overflow-y:auto;padding:8px 0;background-color:#FFF;font-size:16px}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.mui-select__menu{border-left:1px solid rgba(0,0,0,.12);border-top:1px solid rgba(0,0,0,.12)}}.mui-select__menu>div{padding:0 22px;height:42px;line-height:42px;cursor:pointer;white-space:nowrap}.mui-select__menu>div:hover{background-color:#E0E0E0}.mui-select__menu>div.mui--is-selected{background-color:#EEE}th{text-align:left}.mui-table{width:100%;max-width:100%;margin-bottom:20px}.mui-table>tbody>tr>td,.mui-table>tbody>tr>th,.mui-table>tfoot>tr>td,.mui-table>tfoot>tr>th,.mui-table>thead>tr>td,.mui-table>thead>tr>th{padding:10px;line-height:1.429}.mui-table>thead>tr>th{border-bottom:2px solid rgba(0,0,0,.12);font-weight:700}.mui-table>tbody+tbody{border-top:2px solid rgba(0,0,0,.12)}.mui-table.mui-table--bordered>tbody>tr>td{border-bottom:1px solid rgba(0,0,0,.12)}.mui-tabs__bar{list-style:none;padding-left:0;margin-bottom:0;background-color:transparent;white-space:nowrap;overflow-x:auto}.mui-tabs__bar>li{display:inline-block}.mui-tabs__bar>li>a{display:block;white-space:nowrap;text-transform:uppercase;font-weight:500;font-size:14px;color:rgba(0,0,0,.87);cursor:default;height:48px;line-height:48px;padding-left:24px;padding-right:24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mui-tabs__bar>li>a:hover{text-decoration:none}.mui-tabs__bar>li.mui--is-active{border-bottom:2px solid #2196F3}.mui-tabs__bar>li.mui--is-active>a{color:#2196F3}.mui-tabs__bar.mui-tabs__bar--justified{display:table;width:100%;table-layout:fixed}.mui-tabs__bar.mui-tabs__bar--justified>li{display:table-cell}.mui-tabs__bar.mui-tabs__bar--justified>li>a{text-align:center;padding-left:0;padding-right:0}.mui-tabs__pane{display:none}.mui-tabs__pane.mui--is-active{display:block}[data-mui-toggle=tab]{-webkit-animation-duration:.1ms;animation-duration:.1ms;-webkit-animation-name:mui-node-inserted;animation-name:mui-node-inserted}.mui-textfield{display:block;padding-top:15px;margin-bottom:20px;position:relative}.mui-textfield>label{position:absolute;top:0;display:block;width:100%;color:rgba(0,0,0,.54);font-size:12px;font-weight:400;line-height:15px;overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.mui-textfield>textarea{padding-top:5px}.mui-textfield>input,.mui-textfield>textarea{display:block}.mui-textfield>input:focus~label,.mui-textfield>textarea:focus~label{color:#2196F3}.mui-textfield--float-label>label{position:absolute;-webkit-transform:translate(0,15px);transform:translate(0,15px);font-size:16px;line-height:32px;color:rgba(0,0,0,.26);text-overflow:clip;cursor:text;pointer-events:none}.mui-textfield--float-label>input:focus~label,.mui-textfield--float-label>textarea:focus~label{-webkit-transform:translate(0,0);transform:translate(0,0);font-size:12px;line-height:15px;text-overflow:ellipsis}.mui-textfield--float-label>input:not(:focus).mui--is-not-empty~label,.mui-textfield--float-label>input:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield--float-label>input:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield--float-label>textarea:not(:focus).mui--is-not-empty~label,.mui-textfield--float-label>textarea:not(:focus):not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield--float-label>textarea:not(:focus)[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label{color:rgba(0,0,0,.54);font-size:12px;line-height:15px;-webkit-transform:translate(0,0);transform:translate(0,0);text-overflow:ellipsis}.mui-textfield--wrap-label{display:table;width:100%;padding-top:0}.mui-textfield--wrap-label:not(.mui-textfield--float-label)>label{display:table-header-group;position:static;white-space:normal;overflow-x:visible}.mui-textfield>input,.mui-textfield>textarea{-webkit-animation-duration:.1ms;animation-duration:.1ms;-webkit-animation-name:mui-node-inserted;animation-name:mui-node-inserted;display:block;background-color:transparent;color:rgba(0,0,0,.87);border:none;border-bottom:1px solid rgba(0,0,0,.26);outline:0;width:100%;font-size:16px;padding:0;box-shadow:none;border-radius:0;background-image:none}.mui-textfield>input:focus,.mui-textfield>textarea:focus{border-color:#2196F3;border-width:2px}.mui-textfield>input:-moz-read-only,.mui-textfield>input:disabled,.mui-textfield>textarea:-moz-read-only,.mui-textfield>textarea:disabled{cursor:not-allowed;background-color:transparent;opacity:1}.mui-textfield>input:disabled,.mui-textfield>input:read-only,.mui-textfield>textarea:disabled,.mui-textfield>textarea:read-only{cursor:not-allowed;background-color:transparent;opacity:1}.mui-textfield>input::-webkit-input-placeholder,.mui-textfield>textarea::-webkit-input-placeholder{color:rgba(0,0,0,.26);opacity:1}.mui-textfield>input::-moz-placeholder,.mui-textfield>textarea::-moz-placeholder{color:rgba(0,0,0,.26);opacity:1}.mui-textfield>input:-ms-input-placeholder,.mui-textfield>textarea:-ms-input-placeholder{color:rgba(0,0,0,.26);opacity:1}.mui-textfield>input::placeholder,.mui-textfield>textarea::placeholder{color:rgba(0,0,0,.26);opacity:1}.mui-textfield>input{height:32px}.mui-textfield>input:focus{height:33px;margin-bottom:-1px}.mui-textfield>textarea{min-height:64px}.mui-textfield>textarea[rows]:not([rows="2"]):focus{margin-bottom:-1px}.mui-textfield>input:focus{height:33px;margin-bottom:-1px}.mui-textfield>input:invalid:not(:focus):not(:required),.mui-textfield>input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty,.mui-textfield>input:invalid:not(:focus):required.mui--is-not-empty,.mui-textfield>input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:not(:focus).mui--is-invalid:not(:required),.mui-textfield>input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty,.mui-textfield>input:not(:focus).mui--is-invalid:required.mui--is-not-empty,.mui-textfield>input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>textarea:invalid:not(:focus):not(:required),.mui-textfield>textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty,.mui-textfield>textarea:invalid:not(:focus):required.mui--is-not-empty,.mui-textfield>textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>textarea:not(:focus).mui--is-invalid:not(:required),.mui-textfield>textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty,.mui-textfield>textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty,.mui-textfield>textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty){border-color:#F44336;border-width:2px}.mui-textfield>input:invalid:not(:focus):not(:required),.mui-textfield>input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty,.mui-textfield>input:invalid:not(:focus):required.mui--is-not-empty,.mui-textfield>input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:not(:focus).mui--is-invalid:not(:required),.mui-textfield>input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty,.mui-textfield>input:not(:focus).mui--is-invalid:required.mui--is-not-empty,.mui-textfield>input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty),.mui-textfield>input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty){height:33px;margin-bottom:-1px}.mui-textfield>input:invalid:not(:focus):not(:required)~label,.mui-textfield>input:invalid:not(:focus):required.mui--is-not-empty~label,.mui-textfield>input:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>input:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>input:not(:focus).mui--is-invalid:not(:required)~label,.mui-textfield>input:not(:focus).mui--is-invalid:required.mui--is-not-empty~label,.mui-textfield>input:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>input:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>textarea:invalid:not(:focus):not(:required)~label,.mui-textfield>textarea:invalid:not(:focus):required.mui--is-not-empty~label,.mui-textfield>textarea:invalid:not(:focus):required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>textarea:invalid:not(:focus):required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>textarea:not(:focus).mui--is-invalid:not(:required)~label,.mui-textfield>textarea:not(:focus).mui--is-invalid:required.mui--is-not-empty~label,.mui-textfield>textarea:not(:focus).mui--is-invalid:required:not(:empty):not(.mui--is-empty):not(.mui--is-not-empty)~label,.mui-textfield>textarea:not(:focus).mui--is-invalid:required[value]:not([value=""]):not(.mui--is-empty):not(.mui--is-not-empty)~label{color:#F44336}.mui-textfield:not(.mui-textfield--float-label)>input:invalid:not(:focus):required.mui--is-empty.mui--is-dirty~label,.mui-textfield:not(.mui-textfield--float-label)>input:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty~label,.mui-textfield:not(.mui-textfield--float-label)>textarea:invalid:not(:focus):required.mui--is-empty.mui--is-dirty~label,.mui-textfield:not(.mui-textfield--float-label)>textarea:not(:focus).mui--is-invalid:required.mui--is-empty.mui--is-dirty~label{color:#F44336}@-webkit-keyframes mui-node-inserted{from{opacity:.99}to{opacity:1}}@keyframes mui-node-inserted{from{opacity:.99}to{opacity:1}}.mui--no-transition{transition:none!important}.mui--no-user-select{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mui-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}.mui--text-left{text-align:left!important}.mui--text-right{text-align:right!important}.mui--text-center{text-align:center!important}.mui--text-justify{text-align:justify!important}.mui--text-nowrap{white-space:nowrap!important}.mui--align-baseline{vertical-align:baseline!important}.mui--align-top{vertical-align:top!important}.mui--align-middle{vertical-align:middle!important}.mui--align-bottom{vertical-align:bottom!important}.mui--text-dark{color:rgba(0,0,0,.87)}.mui--text-dark-secondary{color:rgba(0,0,0,.54)}.mui--text-dark-hint{color:rgba(0,0,0,.38)}.mui--text-light{color:#FFF}.mui--text-light-secondary{color:rgba(255,255,255,.7)}.mui--text-light-hint{color:rgba(255,255,255,.3)}.mui--text-accent{color:rgba(255,64,129,.87)}.mui--text-accent-secondary{color:rgba(255,64,129,.54)}.mui--text-accent-hint{color:rgba(255,64,129,.38)}.mui--text-black{color:#000}.mui--text-white{color:#FFF}.mui--text-danger{color:#F44336}.mui-list--unstyled{padding-left:0;list-style:none}.mui-list--inline{padding-left:0;list-style:none;margin-left:-5px}.mui-list--inline>li{display:inline-block;padding-left:5px;padding-right:5px}.mui--z1,.mui-dropdown__menu,.mui-select__menu{box-shadow:0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)}.mui--z2{box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23)}.mui--z3{box-shadow:0 10px 20px rgba(0,0,0,.19),0 6px 6px rgba(0,0,0,.23)}.mui--z4{box-shadow:0 14px 28px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.22)}.mui--z5{box-shadow:0 19px 38px rgba(0,0,0,.3),0 15px 12px rgba(0,0,0,.22)}.mui--clearfix:after,.mui--clearfix:before{content:" ";display:table}.mui--clearfix:after{clear:both}.mui--pull-right{float:right!important}.mui--pull-left{float:left!important}.mui--hide{display:none!important}.mui--show{display:block!important}.mui--invisible{visibility:hidden}.mui--overflow-hidden{overflow:hidden!important}.mui--overflow-hidden-x{overflow-x:hidden!important}.mui--overflow-hidden-y{overflow-y:hidden!important}.mui--visible-lg-block,.mui--visible-lg-inline,.mui--visible-lg-inline-block,.mui--visible-md-block,.mui--visible-md-inline,.mui--visible-md-inline-block,.mui--visible-sm-block,.mui--visible-sm-inline,.mui--visible-sm-inline-block,.mui--visible-xl-block,.mui--visible-xl-inline,.mui--visible-xl-inline-block,.mui--visible-xs-block,.mui--visible-xs-inline,.mui--visible-xs-inline-block{display:none!important}@media (max-width:543px){.mui-visible-xs{display:block!important}table.mui-visible-xs{display:table}tr.mui-visible-xs{display:table-row!important}td.mui-visible-xs,th.mui-visible-xs{display:table-cell!important}.mui--visible-xs-block{display:block!important}.mui--visible-xs-inline{display:inline!important}.mui--visible-xs-inline-block{display:inline-block!important}}@media (min-width:544px) and (max-width:767px){.mui-visible-sm{display:block!important}table.mui-visible-sm{display:table}tr.mui-visible-sm{display:table-row!important}td.mui-visible-sm,th.mui-visible-sm{display:table-cell!important}.mui--visible-sm-block{display:block!important}.mui--visible-sm-inline{display:inline!important}.mui--visible-sm-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.mui-visible-md{display:block!important}table.mui-visible-md{display:table}tr.mui-visible-md{display:table-row!important}td.mui-visible-md,th.mui-visible-md{display:table-cell!important}.mui--visible-md-block{display:block!important}.mui--visible-md-inline{display:inline!important}.mui--visible-md-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.mui-visible-lg{display:block!important}table.mui-visible-lg{display:table}tr.mui-visible-lg{display:table-row!important}td.mui-visible-lg,th.mui-visible-lg{display:table-cell!important}.mui--visible-lg-block{display:block!important}.mui--visible-lg-inline{display:inline!important}.mui--visible-lg-inline-block{display:inline-block!important}}@media (min-width:1200px){.mui-visible-xl{display:block!important}table.mui-visible-xl{display:table}tr.mui-visible-xl{display:table-row!important}td.mui-visible-xl,th.mui-visible-xl{display:table-cell!important}.mui--visible-xl-block{display:block!important}.mui--visible-xl-inline{display:inline!important}.mui--visible-xl-inline-block{display:inline-block!important}}@media (max-width:543px){.mui--hidden-xs{display:none!important}}@media (min-width:544px) and (max-width:767px){.mui--hidden-sm{display:none!important}}@media (min-width:768px) and (max-width:991px){.mui--hidden-md{display:none!important}}@media (min-width:992px) and (max-width:1199px){.mui--hidden-lg{display:none!important}}@media (min-width:1200px){.mui--hidden-xl{display:none!important}}body.mui-body--scroll-lock{overflow:hidden!important}#mui-overlay{position:fixed;top:0;right:0;bottom:0;left:0;z-index:99999999;background-color:rgba(0,0,0,.2);overflow:auto}.mui-ripple-effect{position:absolute;border-radius:50%;pointer-events:none;opacity:0;-webkit-animation:mui-ripple-animation 2s;animation:mui-ripple-animation 2s}@-webkit-keyframes mui-ripple-animation{from{-webkit-transform:scale(1);transform:scale(1);opacity:.4}to{-webkit-transform:scale(100);transform:scale(100);opacity:0}}@keyframes mui-ripple-animation{from{-webkit-transform:scale(1);transform:scale(1);opacity:.4}to{-webkit-transform:scale(100);transform:scale(100);opacity:0}}.mui-btn>.mui-ripple-effect{background-color:#a6a6a6}.mui-btn--primary>.mui-ripple-effect{background-color:#FFF}.mui-btn--dark>.mui-ripple-effect{background-color:#FFF}.mui-btn--danger>.mui-ripple-effect{background-color:#FFF}.mui-btn--accent>.mui-ripple-effect{background-color:#FFF}.mui-btn--flat>.mui-ripple-effect{background-color:#a6a6a6}.mui--text-display4{font-weight:300;font-size:112px;line-height:112px}.mui--text-display3{font-weight:400;font-size:56px;line-height:56px}.mui--text-display2{font-weight:400;font-size:45px;line-height:48px}.mui--text-display1,h1{font-weight:400;font-size:34px;line-height:40px}.mui--text-headline,h2{font-weight:400;font-size:24px;line-height:32px}.mui--text-title,h3{font-weight:400;font-size:20px;line-height:28px}.mui--text-subhead,h4{font-weight:400;font-size:16px;line-height:24px}.mui--text-body2,h5{font-weight:500;font-size:14px;line-height:24px}.mui--text-body1{font-weight:400;font-size:14px;line-height:20px}.mui--text-caption{font-weight:400;font-size:12px;line-height:16px}.mui--text-menu{font-weight:500;font-size:13px;line-height:17px}.mui--text-button{font-weight:500;font-size:14px;line-height:18px;text-transform:uppercase} \ No newline at end of file diff --git a/mdot/mdot_server/mdot_server/app/css/notification.css b/mdot/mdot_server/mdot_server/app/css/notification.css new file mode 100644 index 0000000..a3b710b --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/css/notification.css @@ -0,0 +1,136 @@ +/*! + * Notification.js + * + * A well designed, highly customizable and lightweigth notification library. + * + * @author Dominique Müller + * @copyright Dominique Müller 2015 + * @license MIT + * @link Github + * @version 1.0.0 + */ + +/* Notification container */ + +.notification { + position: fixed; + z-index: 9999; + overflow: hidden; + box-shadow: 0 1px 2px rgba(0,0,0,0); + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: 0; +} + +.notification.is-visible { + box-shadow: 0 1px 2px rgba(0,0,0,.15); + opacity: 1; +} + +.notification-background { + position: absolute; + top: 50%; + z-index: -1; + width: 200%; + padding-bottom: 200%; + border-radius: 50%; + -webkit-transform: translateY(-50%) scale(0); + transform: translateY(-50%) scale(0); +} + +.notification.is-visible > .notification-background { + -webkit-transform: translateY(-50%) scale(1); + transform: translateY(-50%) scale(1); +} + +/* Notification symbol */ + +.notification-symbol { + position: absolute; + top: 50%; + opacity: 0; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} + +.notification.is-visible > .notification-symbol { + opacity: 1; +} + +/* Notification default success symbol */ + +.notification-symbol-success > polyline { + transition: stroke-dashoffset 0s linear 2s; + + stroke-dashoffset: 23; +} + +.notification.is-visible > .notification-symbol-success > polyline { + transition: stroke-dashoffset .8s ease; + + stroke-dashoffset: 0; +} + +/* Notification default error symbol */ + +.notification-symbol-error > line { + transition: stroke-dashoffset 0s linear 2s; + + stroke-dashoffset: 17; +} + +.notification.is-visible > .notification-symbol-error > line:nth-child(1) { + transition: stroke-dashoffset .5s ease; + + stroke-dashoffset: 0; +} + +.notification.is-visible > .notification-symbol-error > line:nth-child(2) { + transition: stroke-dashoffset .5s ease .4s; + + stroke-dashoffset: 0; +} + +/* Notification message */ + +.notification-message { + margin-top: 0; + margin-bottom: 0; + opacity: 0; + -webkit-transform: translateX(-22px); + transform: translateX(-22px); +} + +.notification.is-visible > .notification-message { + opacity: 1; + -webkit-transform: translateX(0); + transform: translateX(0); +} + +/* Notification button */ + +.notification-btn { + position: absolute; + top: 50%; + right: 10px; + cursor: pointer; + background-color: transparent; + border: none; + opacity: 0; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); +} + +.notification-btn:hover, +.notification-btn:focus, +.notification-btn:active { + padding: inherit; +} + +.notification-btn::-moz-focus-inner { + border: 0; +} + +.notification.is-visible > .notification-btn { + opacity: .5; +} diff --git a/mdot/mdot_server/mdot_server/app/fav/android-chrome-144x144.png b/mdot/mdot_server/mdot_server/app/fav/android-chrome-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..a445acc28c7b4fb92ff92bf57ecbc8a9e7559476 GIT binary patch literal 1955 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 a0QP^#tePE#FtaBB0000X+uL$Nkc;* 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 Q!2kdN07*qoM6N<$f;x>u;Q#;t literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/fav/apple-icon-72x72-precomposed.png b/mdot/mdot_server/mdot_server/app/fav/apple-icon-72x72-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..f01cfe945175c4ccbd35fed2c49eb10fb099a65b GIT binary patch literal 8157 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 D!D{=0 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-114x114.png b/mdot/mdot_server/mdot_server/app/fav/apple-touch-icon-114x114.png new file mode 100644 index 0000000000000000000000000000000000000000..7d3a7e56cc01a25f96c4dcedb4fa2de7604c1cea GIT binary patch literal 1652 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 + + + + + + + + #da532c + + + diff --git a/mdot/mdot_server/mdot_server/app/fav/censis-opengraph-image.png b/mdot/mdot_server/mdot_server/app/fav/censis-opengraph-image.png new file mode 100644 index 0000000000000000000000000000000000000000..a629a290782fc84eb744b1c0d8bee4da0f4be06b GIT binary patch literal 16511 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/fav/favicon-16x16.png b/mdot/mdot_server/mdot_server/app/fav/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..8fca8550d9e658d65c7df31f14a5ebb39b07cad5 GIT binary patch literal 401 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/fav/mstile-310x150.png b/mdot/mdot_server/mdot_server/app/fav/mstile-310x150.png new file mode 100644 index 0000000000000000000000000000000000000000..e6b2940be405740cc90714683b1c3ea56f6e02be GIT binary patch literal 1721 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 M07*qoM6N<$f;{atng9R* literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/fav/safari-pinned-tab.svg b/mdot/mdot_server/mdot_server/app/fav/safari-pinned-tab.svg new file mode 100644 index 0000000..554fb15 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/fav/safari-pinned-tab.svg @@ -0,0 +1,46 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/mdot/mdot_server/mdot_server/app/gfx/100.png b/mdot/mdot_server/mdot_server/app/gfx/100.png new file mode 100644 index 0000000000000000000000000000000000000000..a3bf76e89bc427008ed197ab2ba16e3848201435 GIT binary patch literal 3811 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 EA1nJohyVZp literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/105.png b/mdot/mdot_server/mdot_server/app/gfx/105.png new file mode 100644 index 0000000000000000000000000000000000000000..f2a4c94893f52974fc73ce6dd9395af9345e86b8 GIT binary patch literal 3993 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/128.png b/mdot/mdot_server/mdot_server/app/gfx/128.png new file mode 100644 index 0000000000000000000000000000000000000000..f962fa8dc6be9c78b10decfcb16a58d718e5e749 GIT binary patch literal 4298 zcmd^D_cz-Q*!?8ZicM>js*xI1vqn|brlBaRMyyoqSyi<|jM_@97)8+;_d(d+6=iFeou|3*`r7B^7!vpV0?l{T!A!vKNPju zAV#q|7(;MWq>!)XrH8C6BBu6FJ3#Pgn4K0YT|_u)lI9PyVQ;6Arq+soV&4qzyLI@N1@f5G5$=!IS=qJc3O>t z#Ok1mStc`G)_(Onk`8K(&ro+n)4KJSWBm0-j_T;&NO54QpJ!-+1Q8xt&e)ww?wuXP z#JclY`}87Dh%rT}Kagy4AhbP_r^T}SOfY6aFncy*7hAE&PGhL&|4TX0NE@}F+y`|>pm|cF<$ga%T z(8aNQeIF2ejqFN=s`f*vMjx6(uODctCz}g^Soqzru=n6Ht?XpR_t%>ewXrW&sV+ws z*k)d1@8w*HMkFkwOl>DnkE95hcA2Jn9P4)-nPtMx!atx0pNh?eD^z@G?y}@0iuag4 zOL}HmgZo4^WxK7&&Dht$`IFl#r16@Sw5MDZq=9KNp#`(m&9E$V;NN4EtWYAK z-b|^r>TnA^PG!}J65x0uAd*!V_Eg6eW-X*7gy&BkxNi^lzJ^e>F{l#A=R*oIrKlLD z-4bFoc*L!xKK)qXQIl$bYJkRvCk&;Yd?IEOqni5$`Yj5sibO zgXP+-HSRU8wc2k_E_X>iBg#DC{E(2E(2|gJD7)S?vNAGzx7x+#qE#gQ?6&9a;B;8J zV>&23>7$;>a{?c9BJqV(&e>`WJBr$}5&aHLe^3s0XlkJOFOyRAD5$(GBt^cB|3ArKW0C*CP^Kj;rG3dlJVrBjMGkI!YF zXGeVDUdx@UT_-K_1@AO5Mot({U}Pck9cra$|7bkp>6DM}t(HhMfo1F0a^vtp!V0x;knpE5osz{|#IVRP z!*CHDJ;y%BxcD{i(HF~&+}>CTdx-?3zgNMy$!z+H#TIEue=>2yx5uMreoASY(nuC% z(q+QJV}k4)Sl~JiSm8rSmi|Jt8Kn*}P8osX|(8$qS zvyon2lMs`w5ZVrCH1QAd_k)O|v@|t(TC|h;fAquS6WMjy{T>d$ziJWS`dUF+I4xbA zxfr5$^vB-Q8d$p@|G7lg5$nd(1#RPMM6G3%gz=KyvPDuF&EH%I zyCzo)RY$RUw_YL~TQcAL)jQTs5XcdXK+x5?eqL~bJLG>e8e&;LTFqYd9K11bI6w}O zbCmOY<<#c;H|o4oZr6>m^7TZO)ojyaKkLrs<>R)kBo96h?dko&hl7a@*B3qG7RHU< z8P&8sbFST6?^SP7H(JJv4_h+2e|2Yb--U7pTa*4EoR$ornZ(Zo-w&3*(cRW zmwv`Ss&<7FN`Alp9mbWEy^jAK)UcB~(>FWWzUUD;21=y*O0CSp%H0~;e`@Gfspj$3 zc5b<%dt|HdcXPW_C^A%YNBaOf0)Gwv(ASmpil8_?DPJm|cDE}rrT5dyi@xWSrDKht ztL2-9GDS^9$UT0AgP(mw-n~5f2h#y@=#QJil>C$W?-p?u1ru`jN1Xu1voa9^{45h<@q6gWV{nX@I)UU5m>LV26Y zNf@PoYkZs`v%dod59`@^D;VJdHdgOW#L?0KjEU9Zj{T{-7NTgu$F1 zGxsj}O7uNmfTlq6>>?DE?;jJx4E0}XO9DXZPbMZGuUJn}^1dxpVNH3GW@mS+vh(ul z6b6uY#>d{5)ag~4Tga-℞$X9i&gg$MC9p2hv25t%osz1Z0ir;v`zcR#hX zv>2P2nawxy`lHeMOiWDEOn<1TsLHCVC13gY_boFx2mu?#XENnJX;?L^LqoB_J#&CYGq6_9N7n8@WwUSD^-K}<#m1n5{= zS~672k*cNNn7jd?O{uA=(@Zio>6gLg8vRHMi$~qv-FMSK0X{xy`Q+j0X+&U1$Z&LV zNy%7Om-_GR^Nr?zg!4ec{fmmy{?yZ>qxS>?VLMu`6+u2bbgK8vnVXrh$j-^pMYaV8 za5Ps}Rq3tHv#@l{Oih`y|4{?ZE9U3s%p1J>{$;%gyrvK#r#rXJz11!!>12106#3G} zN46azZQlI^^Pw=Va)$=+syIG5v5;3JLBUO^a40|TUlw!)8;-ZS&;FyAdl1+kpfodh zoy)DVC)P)VNB*md@dzvlfdn3MXG6a9i9Bm0(tX~OGgW0`L&U4aE1KNcbN(k*Ha6=hW%+(;(H|~k=spXhHmOFV z#?h#2cqiuPmHL>>gXD{Y6}Y-Y*bYBezm$r~^PlO8^=QU@7MQTG@R?xbev;#z6#Vh= zu{{geQkjZZv!njUBGA$WhdT{SvX-oBODt?+J-3FkxQE`9i z>;uZ#`4*adB3=#~9v)st-I6ntqm8@?NC&i2+%h`Oo=9cTma`E{!(fI*f-ooTSjA=N zl9P(#5s^qN*(ai~Nv!6y!3#@k%9QRDYkDorzanoRSKBTje@$houp?PG2HV?+#%aeF z#_J)sz(jinx6s<@=gSMg`F5-Sf4d^&JMUQ!>sQ9T<{0pb> zCikNJIhJHXD+vF*yqa2?1%k~j+^2Rq1GdR(m>t~JU?Eci_q!b$3{H7tV?&`Tv-4|p z(2G$=UkM_TTK7`O$+X#lO>*ZXB<>VPY2A4Vv<{G=bEci0biA1DQ%WO;WK3HKB^!Uk z{kZ*`(4V26rI~zH>0BIpAV97|9%vJj@Dz%D)ndK{{xc5Ct&~p literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/censis_logo_white.png b/mdot/mdot_server/mdot_server/app/gfx/censis_logo_white.png new file mode 100644 index 0000000000000000000000000000000000000000..10631a92765696f1c81aec014a99c0be122d51e2 GIT binary patch literal 5975 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Cellular Network.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Cellular Network.png new file mode 100644 index 0000000000000000000000000000000000000000..901c021ff0d97cbd992fa0ff9860c8951b1547ab GIT binary patch literal 2203 zcmai0YdjMU7oK5eqlP9VrYQIOl3X@I+msl&%r%+YG^Ia?}zi8=lPxI+xh*@c~b1{PKiV0AOHYB9E-8S?{>ex1qSWn zr5UOd008#IT3I+<^IEu{Hl%eDmh{br0)`13LJK7WBoIKW{}yuw&n}m zk&fXw&kytDv#4RzutC#VHrY1l<7@nzkn?O%?YQzd`dDVCAv6E@q~-r4N^;kJM&!BR z)V9(WGVl=8yMdF%5ueT!i$E6`6QfS;pnef86%o^TC71%jD;>R9XbKY_X# zLh*1P2}M+P`)k&#=D4;f?a&P1a;#cn+a4$^^m^EnBXMn38_#~4^LiN|Acb)t zeid~~Gvy91{~aNrT1~IOt?!K&COG-y&UrPiKB++xoVxMdZ_0-U2CE9$0^5_5#5mV$ zjo^EhJ{(X@FiEeXz?d~+WuKDFn}{gf&X{>m#}%jbq%zpAC(kq}G~H_8WyYXbKF{7? z@H{9RYn}E_&dZG8j$_PJ4Jf+3v5_4r&De~PA^5VY^~8K+wVtRv`}KbBtKW_qH-o?NkK++ z=h1F-9%GONROY5Wb4O9M5w$dE4_Vs{sciyPkP+5K|w%he|)&BR$+=C$&3E7smumW z%yh-NaO4C!47l?U)6|o6wqir^QsrKH^+v_@7PKk<;W4UctDDS=c0wvjz1iP;D7Xm; z?+*XrQKdRTRQc=Z@l#M2Lww$Oeecj)fDHc9RwI7sph~EVCQo=dFUyVi^zd>o=gTyX zNf_$uFgem88~JMR7!>;u`3Ym|Db709$`?C)fsU@3sIuSHc3+T6Rihm2tm4}8r{MQnhy8ITC0RNZ1_B=~mC zXph81G3u&?uIi*eUM+ly0MD`kQE70z(YC%J-G5zBa40OJWs~yK{AwAB;mYe zKLx*Q;V(rGr^H+Cvn?5LTd)=9m?=CukPHWphNVzpw2ErD)xhU&Rfx=47I(JWoRHqv&r4=)w9Bih2 zJK9}fB&s?ayG8&94E2wlWh)nct$k6We+`=4sJ|9$zivNbRboVQ&-o&WV7>7|s`(rN zBBMSfHOkeh2QiTUj$)Sw>)r~M`Wbp{V;U4R(4aToP>Ak$2Eb#anR5o~-omHeES)5- zLOw1es6uFhOU^w72TelbRoz9W`zubg6>-1)WK!quiaY(R;+pj~qm}%~xtoyP?Z&h+>YZ?Nm<5 zVweaQ#>U++`2Bi_J$XfOcTmWAIxpKq)vh`kYDa(BZTaF8ZTRpQCv6PqhUf{Q$LaId zl84nDDR*$*TKi!eGt!8FxZ{pW$zC5ErQ+4lFL*usBbfWXyO5l+N(mJC0Hg1THv;z9 z=xn#|L6@$as}MOD(EH=3w1XB+7(;!|Who3re$nR7dft+!&UR*V*iF+?&s#a%mtG`+ z_U+@TH&tw+7rFyZX++mME$*Qi(G=myGxV@ugL(YDhl7PBFPU$%p4WD-o{yAm9rnev zT+aP`>c>NCtcyU3xqRm9LG7B%&CFTONT8|BBM9c}1*2gf-G>useS3oW zq8SkLmG#Z>yoc~(%Qi^qzZX~fauuWEtcVZh?7$zx!*ztejoG=lVyI^}gh)>0SBe2T znR4CDp(S-A&4fsgncDRBPgNC4MKJ>Lu?`I}pv>8rRa+D>x-3zi8tLuNxY4^gDJ9BnwSOb|MN!`YRrzebZwBjP`gOWV8Z+= z9#E~*XH7h`qV6)>1Tb*v+pqiC4roHLmWJ{0Wfg>M1L?zGX~w-L?w3lK4Bc!Ntg%C6 zv&{{q>kdUu$JM1rPw;oY`Ctg*K##AS>*@O!mHt230XVdw5)5|=5ATK!0M^>hs@l>g F{y!%#4x<17 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Chance of Storm.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Chance of Storm.png new file mode 100644 index 0000000000000000000000000000000000000000..588c15fa578a47753c80725bc1ed5c6fb23e8eee GIT binary patch literal 2112 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Cloud Lighting.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Cloud Lighting.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c384674acc0d1c24d9a01349d3b2c9380d5e25 GIT binary patch literal 2167 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 B$ff`Q literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Coffee Maker.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Coffee Maker.png new file mode 100644 index 0000000000000000000000000000000000000000..e54539f9a77c3d4a9f5db3b9d3ddff1e120037a2 GIT binary patch literal 1311 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Fog Day.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Fog Day.png new file mode 100644 index 0000000000000000000000000000000000000000..ea53a10465a2a29982bad104894fe57238ea3ffe GIT binary patch literal 1452 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Hail.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Hail.png new file mode 100644 index 0000000000000000000000000000000000000000..250234694ea0671e3062f3f9fc231a0752758d40 GIT binary patch literal 2022 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 bZS3b?=VE7cJpkp!00000NkvXXu0mjfVx~ub literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain 2.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain 2.png new file mode 100644 index 0000000000000000000000000000000000000000..dbcbbf14d615bcc6bc5c49bf7a33251ad27e4e26 GIT binary patch literal 1883 zcmV-h2c-CkP)7b3V;eoDgY{g`EH)yEPIwL@7lZa zJA3BM{kUDPtm}hF;QFSxMSBKN zKB&~L=9fnR!sh+8F*8gOD;=TkX#hvF-ZDCQetFiO=j^)oY#;~;?a&(L>C=Wm9i|Zt zv-TPOpVL+XOMXB_Tf1Ze&Ia=5D($fZ0}KSy+5_@H@vL&-ptS^>&Dxnjh`b5>a_!A! zQ*I3-J*yQI`U4DR_oo(A&IDp<2X1KX=3Offys+PDZ!)fL64RUognfYkFxQUUSW6B? zEibf%Ky&l{auyJ5FA2k3d)#5)&;*O=LWq{R)A|Q zAytq0Sql^shm*k(K&b(Rn5H`Ae>4z+wC^siY;ICaV$;ehNyzv=T0){RMgOI)xSqI( zpQTxwqW`0SFbP0dtDgX{XLh$F=-U6YxPWNIG}Zgz5kOFNg1?fm3ARetw7rG>h)v$rdIBk>Mb-o46mM_7$~EZ@7oq*^8Sf~4 zyS1bj5U-hH-(YpIiul_rGVj3PUYFJabZdVvAf@Q=(%anjt00+(~vZDCW7N*0cqquR1Cm^-dN4p0fqJt%7+#0YHSS|ioLHT*_Sb8HdxmV1E0VszJn zErFDhftVi1AANwdMG%qh@tm7ngT^Hg%T)EMk%}a^o?|JM9bHrO35cZ~m?6tg>1!i*Rv;V1@$$B&Q5Wf&xUa7s8Vs7dWr6{4LpuK%*!QmYc zQp8lI=h{OlOz;Y_#dTI@20%O z&<+-Vu9WI7Gm?N<)JU!1am}`00=x#Uy|i=}h$kSWT>W%`_rtLE>g$=)^2D(8ittEK zSYVONEOiQ2P4hKPwFFXn>4Y_c`C_AwG}-mqWnocUOL5-W%~NdnzpVPY>V#Z9*#?No2eYWXRsQ$30j# z5YyE1vlF!w^PcHj{=N4Yy5!We^h+NPTZ(9iTIJD!;BFK3dbGqF95z_z+q)PY2s8I2LWlX1#4P{; z3a&5F@cLU-m?>hFVZI`9D?pNsNM{l$Q8?Ti!?y-xyYUWk=L8Z2L>k5fGJyn>K(OIV z4VgfKNg&v8riM%)!6XoDI8#F=kYExBHk_#;6G$)#1RKuOkO?H11cD7`YDh33{{cdT VRRJ&4yb}Nb002ovPDHLkV1g~mYa;*v literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Light Rain.png new file mode 100644 index 0000000000000000000000000000000000000000..74f61ea6e412621d89c87dec348be71b5442b21b GIT binary patch literal 1816 zcmairc{G~~8pglG8i`tBFXk&riEH0_si{=$O3|bTSBT|Of=f_Jt4TX*yH#3CRZ%4w zEk#sr#9o3}N-d?fE@@o5w5mFma?Q-&bLRb>_j%5F-uKCHcXN=GP>}!tK+?(4*7L}N z|Gna(M;gt`#{q!odnenoxJ1A8l8^bSW(Z2Y1VsXr$LdgUz<+rPRQ(4}NICSLgt&a? zUcooUDblpc-M-1;e!+ZQVsFD4mxhRSey(jSjp|Ta2@60`e*Q%ma-`!Flb9|WXu65y z&qyuZ{}(Jy>hb?Bb5*lq+}f7UG$9mo*l6&#Ozxh>CN=#UN<)AP`Io0{3Np9Mj<0y% zTs5v)1k^r2%Iw(KQpU#W6*{euGFWzGDfRLGZ?^pL;hDW{L@&+dtAsFXtL>#8v!ToR z%;}cK$%M7dM-HHu$VQlL&?A98B3P~axOB}ER@Sp+UfK)h#IEE{!Ub%Np1pkQ z0tV&ntwEO-221i`oKO!ur_PRFoyh~vTIaFo47-y#Q=K20?b*)w6e+A%e}{tU{&!_z z=lL;rb8KuzaFU=ebamEvm>wD`^s;T=n`^*r%D@tAEkC**(scmVWilpEYI z_0`lv7o#4wL==Y#owYz+XNw}_#*=xvP`R43j0UYyzQAEss366JnnMjzW81e9mCVb}(Z)!6BykGz^sVRbNt#*0}5lKkMc_POTt5Xj5OecDhWKkA>2 z+LO?7>q~us;eV`oW5p-D;R84;+ z`~`4#dde~39kX!ND|2dLXz3Lg3pw@^j56r?Z+QO0Bb5ZjjjUA9)1_hvY36)@tVosD zz%z4MapYkuxz5P56rVW|CyD@EW<#&|cbc#~B!~`QFD~3%-mwrE!Uc~tvk-#=Y=4es zDe;?GbxZMpIOvtS@HXgMI2k}?P>SE^{)+dVJD$Gq+R!xgdNJ#(9Mpx~v6)*A^}x~adceOBSy^;5TnTi?TtZdJ$#b2OrqyU1$w^;N%no7bdy zc}6CCJ7R?Xtjv28hmv+0Ek?dm#}@R2d!;GBFNrj*kT<8wySCqW}esSYlnKmNl|XG>%nN4 zxS1#Wy*mnD00w+eZxZ3K8y z^m7ck=qfGiNG(WyRu}BXR4CN?IU|JTfCMFlR(uD3rxW zZBB>8bQJ!PYq@a3_hihu2PE~C$h)GIxbxpp&kglrtxD<|b*b4Ss*>qfdXg=bov@9c zkXzw8pI5|*JI^#BnAEh3Meb0~z4`4Sz0V$$ykjx!SdF;WRzxN`iLb*!UJSe3qY|QTM-+uB2o`oiG%kkM_+2QwkW?! zZF9?;YSzsPU0UmR^OtGfb+o~ZGv!`I%5RoKJ&+qSqvxJ;f1=ck15s*)^pt_8qNw%u zx3Y^H^HUkI^Rs~`Gy}Qfg?79&^(=Ig0_b#SQiErflYI;&PZR3OJFJ0_pI#o)|IzF2 z(xpqxJ}R4fr0fbmwv$S@?nC8^1`M*cPoX33lki)5`fv-fw^8Q6^9hA%gLq<58tnW9 zkPbO+$ppfbdiyjX9I-Tl@1)y=GYDBi!9^h)~zaR(o)F4X((5Yxq3@9 r2jHC-8s@;@FmTxP!}&+`|0~#0^rr=l<{Mef14rXz=Vn`LL%jJH(ppH{ literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Light Snow.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Light Snow.png new file mode 100644 index 0000000000000000000000000000000000000000..c804aabe989485ec350908530f344f500e517554 GIT binary patch literal 2032 zcmb`I`#;l-1I0hP+Ay~nQre^&Mdgwvm+@WMT&8Btr8SpayNVvvqLC0?u(?YVij^#E zEv;DdG$FSbt0>zw!N{CIvkR}N5IQL2Wj005xKBqH?>L;h<7 z{7*)W=F$K_MMx$()8d)Rl8^j#HtOtLRUC$32K-NK8c+?~1E`=1a2c2cBfvId08H}* z+ljUHT{+{8;^WxGj^d?Hv0{OvdtQjrF{eK@r}<9#{(88Hnk+Cg5adUIbD9HR_!&N8 zt8Y$fNv*dI0j==>UqXdP%D|QdQ25%{y;-n|Lg?`G#d$&cjJ{&WhHt|3m4PX;N~|>} z6*qr_ICkmFNU;VUG|tjqCKH+XTBlz*YuLaCZ|&v#RR4(A@(q&JptmwYclva#qMOQ& z=DF*OO;}gJmC%q)U0XL;KIRv{({zC=H;{9e;OeXI}`P? zNH)GELF2~44!AoZpfWF8)0S_1NMMWkWgJ*1bmp=&txv;Qg^w{i!<1GlrM+~p`)_uJAhr!!f*QNwsW5><)S-O}$T!05{pb&6jnLvwMIj;m zDRPCXT=>iT6w1V&htd53Q4d?%r)Cxo<~KlW8_v#IDWVhT(RrfNA z`^_;Q=Q@UCqJ-Yx8ZZ$j{q#YR46@DTjLm;ff^4psHy>OxiSuDF`wEr`Y!TB1ct>`M9 z&Fd8&c0UiAEizq1(e-)htKtoF8tUuMMw%0Zi%Z}f_q&|ClKR3!Cf3c{@6(E~OZw(* zg7t*xpZoa}**9DF==;XRiRK##J3YUT4t7V)zbYG*H2N}hF=cC(6j>1G(>0=RF_nb) zz^!x>Y;H{GrzCAqOqbYp_Y&>IsQ*?slIJf<)7|^W%JxmoI*_-T;zVWFDIoTw z_F!f2cneCSP2v|rW9h+TUM{=@y-GR6^Y9H|nf`l_ASZ`_Wd zF&Z`kd<|a)zTgS}_vx?Y~W_tSdgWYgrek zFm~YYCr9o1@Gi|LN6+3-C0%cFWX`#FsG=c$x)LVMwQyvGaU28o`dxr!UF4F@r)#h$ z```K#ejwjZ4nc39+-W5z-!utZ^|s+GoL3qr8VjCMSvy+ay$Rpu);&Bn{{8XyMs{AW z*L)=`O&?d0UhU!4Sg48)J43nOA+us@t;{|Ps1dpO*gf2QdZ`}ZGw-l;axxWvQ&RJF zWNR$NR)F(f-<4`=jeFRiard(QTRs_<@1h(F?|G+mF4QO8t7@@)9Dt6nKF5T}nf_0p zqac!nk5jVRRlxKaf|q$2Tu>%nk2|q)hCh-$P99(;?2XCrQjd9vxP{u33x&bY8PoG& z8wWDt`AxjuZ8j-(FkaPiUR6fY7}GAuOdToXb4v( z!CgZG1>+q@dCQxZLU^AAX~0uX&y*ccf8vGN=Q;aJ{-DqKZq@Vf;KVF*ALz9oK^D=Q zvez4P8JxEf;#*4hLKlK>fZ-$(>U|aOor#JeNK$-rMP6hs!anY#1_E2#@@DGXxpa}Q z23ZqV4z)e}X$qDMys&lj4HDbzha}gLQU>UKhp|S-k6T9n)+AGqRUvl-H_HY{Dl zq?EwN5=X%07jI7u1gN?tXeRE+8njZ!J~E~JoQCC~BicuVrkuQlv}e~n$_qZ-0+D1| z5m#~y7C|42Ik`MYgP7^x}FKp7a?2~Ocx<=mQ;*FG2v9+V2ZQ+Y>9 zk))CpX$P?NH$7v^uj^GQRv4V7Pm?`b3!3he)?OTK;y{ojq8(SWuc;lgz1RCQ91`65 z5K5{p(P&Bp;XU3wQ!&Rm;*Dba9Y8&cklnvW)0cOGi&fsEv+6?z=S6BH?=u5&0`{Bs fx=79cZ&?K|TuueujwjCkd2)cfk3y_<2~7SMOk%HZ literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Lightning Bolt.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Lightning Bolt.png new file mode 100644 index 0000000000000000000000000000000000000000..20364996eaec7e5e44f7f767579c5a90507afb20 GIT binary patch literal 1247 zcmV<51R(o~P)6zKLXU{o9T&^N;=4v!C7z7Y!AA$f9K%7Ou*>EC50*JE+I2%r6NC0sb0cXRB z3<)64BH(N|ks$%3N(3GPxT%Xm?75yd^bey4uDSv`=O?%2;>QXmxibX z5JRv^OuqoQVYo4X7=mRrwN6*megLsX*NBBJE;2r z-UkqEDC^i!!0$5C)jDe;L+Zp^Y=r{OZD(HtAfa)&0!RlS(sXqbz}EoMfx@Z_PTBpL zkWeB+8ncm<-4_5zXk1?bq%jbw5OqCKmJJ|{fpE(1H>N-pKpFy(l-;KQNNC(%0i+=i zN!d+JSMj9Y5C%2PO;?Muo9aF?q!AR2vKv4e1wYj+r|gm~6{1Ml4ImwXaD}L~vKv4; z0g{>E}HUV_ln*Kg-6ygSM>}%4~Ve5|o zZYSJHDZ3URTU*zFya17u-EAR?`v`ImhPjWdD?na=NXqWE5LFupmqDZo&@)lj%L@>$ z5XC9Gd!{UHfVG*aZBJ$A0Z56m%Q;7D(DHXn6#?Ezo0&Vixp=z=ASKGKHVCDFESaet zi^|Re5Kh^pEoy4lrE-ih(gLE>^xfAF8uMr%xmOHY21QZ@mgA{=;1}IH8c38NbVJbR*p;C?4fU5jRYboy98p9I~K{KCLC_v(y9VA$8w>qkwB#B zD&=r3K(w%vOq05}0~E~wY#Sa0L{fIO&X)ojwQi~W8U;jBc2xsU7-@XjEAf|(O?{un z33X!zLs~y*Vcq*Qz3x)ui?o>MDv}2G%1t#+l((+CQ~R)%Yfa;ewHfJnQ#VM1bx_AEfSdOdw)?wPT4I0KLx_4;mrW&qN%09GB;3_v(Vd016Y zqIh&5C$pH(vWB><3eK7#ZmWW`0+GHjbI1`N%?{wmYl!u=YE8VF+Z+{$R308)6`XO( za$Oai4T$@y;A}wL9`VsEKu26d+#d0n5y(kY1!tPFPNFI}3lRF22kz@+T~!5V0U~`N zzl$S2v#lZY@@A^~H~hS=2E-B7Ue50!?+RKVtZk39?d4+N=7^65($Rsmcr8v7*J7Ka z195f4M?>kzK-?YiIU*3M0xmyKk@Js!Znfo0qq+Wz{(ov2Qsm?*-4sBa(Fz~|#90KK z4JR@rfH;eQv*ARB1Q2Hta5kLCkO1N=0?vjL84^I8MZno`{sB_i4|IA*Advt7002ov JPDHLkV1jsIDBu79 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Moderate Rain.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Moderate Rain.png new file mode 100644 index 0000000000000000000000000000000000000000..116b24ffa729097826cdad4bcf1f873ccd6b88dc GIT binary patch literal 1861 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Day.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Day.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3cef4c1ad7d2e01b15b5cd9ea3cfd9036ffdc9 GIT binary patch literal 1730 zcmV;z20i(SP)!wCxsAd4xm*l@x^0*HJlBJX5$crGIU zET+%&;T&Nhe~QS*nVEhsBHv9{V6hGZNC1(r5M>dBg@lEKg=lM_$3pIl$YT-tNko2e zEVL0WtF>>(FpsI)3M2_a2uu0e0i_p6Pv6I=?C7-x$X1ZlT`iOzAiaG%q&cRl7f4AE z50q9QBl--)XeR{^E$!rfhqkds;4D>Ifz(1-YO)14iHlvvmGuC*6)3>?^s>(!zJPjx+!B;8 zME=bp99l*I@k06QGVyCS!5+b0le;IW5$M&WO#*`JLNrIa?^QIigr$rELL~H5L~`M5 z(&CTH23@*@q7621ermxG%KlifIRl(_zcj!A<-w7A$|xX2L*FWstv$ul1W<7u+N#DP z2*15i5^eK4A1Gtx|8ZZ3lo3E!*?(Wo3%N-!IgfCNhPBaduHf=;Lp_lZ$xzK&usRk6 zeb8S|UoNmCfM^HBmTOr}tPwDhKo*p1A*UTEM*v~4q(rubM+@4Xl3O{{$J%lQH-%+v zH*VJo+*GD5&3$d#PKVXqPWl><((91zAWNYlCt*zAQ?$LPr9G=}Z2@S%3rNl`!(EvM zq?DDlCYk>KqsrBcb>a53To=|++EZ%BQ>y22UDs{w5+?5n#BztYpC2moR4sc^EvQy2 zq5a`djsimV*W=D=t*sV9&h4hRVw`O#xwm7v_JP9qhCK2+0tg@gQd{J(B zx##}j1*io8xGd5xUB%jXYZ@=b@>?^uq8Va)+}X%;M$P!Wb+oe!ZmTO}JOT(wJEEmr zNoH(CGM-$QSHRKrwYhY=*AYOp0j3CqJ)i__j|1Om2;25b*52*5MgU>3mTx7B$sO!k z(kpw5UDLky`i6a^IRqXB#BxccNuJR<(p+8_CZ#=RGGUJbQgcC-8%*~mXwGoI3MC+^ zM*XCd+J*H3>4Cw3ZygA8bmhBxfb_z+D?k#Is=NADARZX$ zMM!#Md+k#(>EU+@E~njI84bu-^F!2Sy=%7*`nuI4&QW#Ihp@MlgfyQSd4be?j%L@48dIA(DJnk^3A&eMiu0AzJ!mx2O6ig2i9DD0vG0LIp>M zY-t5TW8`E?sph*3MT3EEst4%-qHXSU3=}e(T`&1gWEHq4-kxdikj-bYJwVW^^f}wL zjsT%v`ind#(%2j-nF-SDEKVz!Veg>6dRf;C#LE4fGrA)cs_%$;fuN_B`@bW4o71e$ zf{y^gXu?wROsXv-{rV^%2@1(H>uV!(Io(JFlCA73)sN(u_edZ~M>Z~!YPH|!-H85g zr@`jUIm7eUE8hO{9zas#>@9?VtP;=1`DX+K1OSl1==$JjParvAZ|%N)_(Q+hK+d@O zr;a&*OqJX2EP&V=O|20?rpj%17C>x`rq&1`Q{}ch3m~>eQ)>i}sdC$$1rS@KsWk$~ zRJrZW0*I~A)EWU~s@!&G0mRm5YK;IgRc^bp0Ag!2wMGD$D!1KP0I@ZiS|fl=mD}#@ Y4R>BdbWbP{^Z)<=07*qoM6N<$f*l_!MgRZ+ literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Night.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Night.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb14a58475531903993ccf5ed2d656d1a79a639 GIT binary patch literal 1834 zcmb7_`8S)18pmU6L#u*XYO1^^u%%Ao6E9?Ku)ZiVGZp=T~`X0>(A@J;^v_-&~|aiF){FVEabnWLJ}Ye?ZJYW zV{B&X#C2R5cdHQnyj5oPYTC`3bf<-Q+(Y&18zYKeS6!-pG`^Ri$3(bhck z{TER_AISk_!C3<NN&L5pbmVflY9_2?c zvtWVA3+CvpI~_gW?F?_L0QP)1OwW-TiFory(T3ko*jru3EAL}yLmIQhdkCbxS)o`{HF8@3-@AkS{Hj$-_z#pz~FGy zkDl*lXoutFICZqK5_WPb1K#F*5g{$ni_gTgTiUkJ-wVtV;2KJ-z&7ACjC!bkw`ZCv0VqRLsk*X}O3Bia*PR zzv{9l{z%>v+SHzAsaMp({Z2VO681d9{UNXBu|p!&iItT1g2RW8p~jhH?$)FjJWSTh zG3mX)dLv<;2n%K%1%lEx@AVn-z?INDs>BLKl6UB&npnP&m238rf)&&oT8j9=6&~Lw zhsvK|v>X5JK>0RgH8Dtefx~q;)3ic+5_g7c!*R=+E(ZZQlpbjXcE*P$2wR{lA#d2T zo@9mshq;o`%~(f5WvdK@nx#Zsepb1vGZf+++pv>Un?~3uLTC)0<>UuOm?%*g$(-8Z z@J*_P7Aeu)PrV>aEnsx2XBQET0eiTgTJwe#&lYKYR0bKHrCU&fxi0zfr|PQgdNF~L z(=m>3y3CzCx;a@@O-=;V8)ggx5vgNI*iUm+LbRPE&|Ko_CJD5@rtE>n7`mjYgIjA> zt2?xIg-EV{>325;)^mGn+zOSkge2&qZWC4gP}1)Qy&4vs-;eLrN#T}?NyeSc)U-z> zhB+ zKW&YGjQe>T8PcMLkVxT*<)+^3UIqp;aA!B$!);mJ^_z1FRqryNNLNr30hE0?&vhT; z+|;_ietOcb`+2cmKC*>;C(rcl!auX`GSTyQq``(S^a_k%YDybf==CGj z&p`z$=3P&1=b->wYDnr`o&IdWh)f-^Y&41bSqH8Luu&Ni2)IB0O0Ltegc^V^`AV1H zy40_v@Wvo}L$|)g9l_Z49!?(Wax5;;PYs%Q9?nk!Ji9waCT8n$6^6RsqMAsyqadrg zY)b0*!h2^*_Y|Q0JhxDE{PQ09WaRastC`fV3g0W6nPCs9Bh@zN+A4sNOykG#xGM=> zEtxNV@tib@Ou*teiqAKk)dp|)vmHXvh!{Ludzroj{2j8c%$9#y6$V|VYHgKh&vz@z zUx{4#X1RXhU)PP4w~^;Ay{e8@ra%16OkoN6AePg%R7=r_;Z4u#XO=$DG<&HCr}(ak zf+AV{Wc|{W>k=YK9~X00ftoRQQ>dZa3N`5}3~W0zE}V`FU%lp%*4!~(Fe$VBRh}m! zwrnCiNcvvbp@(O3wM%V52b%qXLEvEF0x9Y`@dN-7r{ky3^wZN7ii~k8aqjeOX8OVt zJv&{IgxxHzMWE&J<1Mo1WsI9fLwMe?v&2gUKQ-$`7#yrC9*BTi7k8yWOmO1->madN zW-mk-h7s~uj4R8c(4;-~lugwx`tb6j2G@MSzaT5s+|yvepcF+A_zQMV#o8AKn>)?t gGe?R4zs2FHE;)ywBbZ~-aR)-ojIFWHK)2X`1B@_JvH$=8 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Rain.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Partly Cloudy Rain.png new file mode 100644 index 0000000000000000000000000000000000000000..a4ba8e0b75b471bd081a483da187cdacddc999ed GIT binary patch literal 2115 zcmV-J2)y@+P)RDcRl0aF1}0V+TRsDP<}sQ?wA0;U4i@2)Si&dojhm7ILvJ|kJ{ zt~=a3cJ_b2lblCowNxB=6M_ZE0wfs+l997CWC4w`83F2_VrUK<*QQ4pTV(*c9#IzV@MQ~UO;-*eyf!7-9;lt z8T5TA<>{@GR|$}BE|Ml~PSX^a^I<84IrbX=|64&4H8AR2jQxBw@fW3(FGo>m#q+YLBBTsnEcpl>xt_=T@K%u|HH0F4>DTC<$G z2NXbna5ST*VY3+zI51giEf@qFUhsS9s$<{*+H#d<0Rj;gDAyo#3kK@}1`(9i{<=g` zfWEDt)#!`guUV5^wB%^BxVx+ekXwV&f`Rk4qNwK=t@9KynG0sWX#hhWMkF@1c>%c< zC@mOBG}|L`FM8p6#*m)3R2oiC=8X(Nm@p4%tTkk^>R_BGOwk%q2@YC1gu?k_CNybe{&$-V6Fd-A?X@Go zsPkG{xLv>cro$4-sD^0HG|CjfMcOoJq$*I`ABuJyZQm{PwI>t=Kf}O80MR4|Fko=B z>|lXX%QWOTQlitK*%*bB@AnWo^ZOIgR)3({mh~#@^>v9XCCqzqCi*60*DsU){Sh<20#!6 z&Ga8G23|T@CfBXW833_jeu4)2xYa(w$piapn&J+8Mgc)ev5_N9(~huH93kX@u~M{% zFL}c=|0p1=!9u-vb+uT(JsI@u=hl5R)8&dry?F>W8%f@4JyJ~A2=V+#j(G&=TLL3R zi!MHS0bzquDFNFK`j(au9&^_2IbEEc@XZ8FGF$azv>sXS(hvbeb6VChC#H$ZcHW$& zE6bh9<-pul)d9gqTXswL5kO!jC`-wkbRnSUR>-Ri2-spxsC7N4GDHAjA}d5C2?G6U zzC6dRd&2js15)?=z^_CB@nqD10rF^+b@nY;f-?hxP~t1S?H(u*Ks@)RyhPBCIvB+B z(*^{X#_WlpwpSuY{3cPP15>gqkjab>H~ot~(_mO9*NN%T2FyZ2f&^ISGNv!gx| zb1hGK-18iv61P{ulomsa&^9ZZKXT()=hDhhPkWyuNabXya(kviA<@xnA19Tep7lIO z&}#d=k94v~Gr1E&g#d*wC#(om-+wiOt5U?p-Tl!z-1`}2r0t9-9qO9vSXV;KD|K~cx=m1PQ$a-`gn?`U3+~w_Y6R4-lEn1=~F-WQcnzfKaRPz$&qBvx+LA2I`8d60N^-+ z-}Ua9W;X9V1)K#41X$6F*C%MEVlTn+zBlyxk1d@NzpSf2+FtMZ)tP`m#OPNbv?m8r z{@@LPMqCTXfSbl&m=GewH<;L8xR zHKY=OG{QjdQ7_}P*IC*jPxVh82k+Gq{G0Tl8|$omPt)*U!#5Xuw4)t^wm^*M>6%tu z_LxGeI$deA7z!9fWKu*J`4A3!SHG8XEe&abK{D$Xd87xF(s_iX9ox0MFPD&hgk^hG z2mb}|+E*#8xBF-T4j&L)pW(O_AbZ+YKUP`)CMAy%pXBu=z1oj(w9hH(2R6Ir%mj#c z1CfXZr;V1JrkxFth`FjDc+FM{(9Q-(wA=xcvlTQ|;Lirg(vTE-e4mKOS9-MkA>r11 zm#woA?oH;P+gsO4v&XZUtjah~;WG0%z9;}^1%wTeVFOH?^;2>oBet$BrO}ElA!i1p z?gJB6>rD8U>7R0)iR7yQ$V~oReeMOw)mg4DxByvzB;!Cba+ZcHK$3AF897Ts79hzu tkc^zAAq$XX97sma(vSs6G7cmo=RX=3(o${HHNgM?002ovPDHLkV1oI#)olO( literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Rain.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Rain.png new file mode 100644 index 0000000000000000000000000000000000000000..bbb063a2b07a21d944456f05df4277f1a65019cf GIT binary patch literal 2130 zcmV-Y2(9;tP)7b3V;eoDgY{g`Q5qN5ni2#Y`wf! zn%UVuu58KQciuYoqp-$Q2t1lFg{gV*FN7ui% z9XLVCk0FF#LkO=O^M_A410fLbc?jW)gJ_{S--ZzQKkb;A5H#Y4t2WdG5UqJSt4W)c zkS{|B--Hl6W@#^3--i&M?Y+3wb+Zuy0Y5j;3JE{V*JmMwzgq!Zdf%A{fs7X+g!c;{ zB8{lH$9sj>W5Pb3g_KzcDIw#J5W+9lKPj|@RQ|ql5;P4dvk-!25KU?0)zz<*Mo9z* zguXFvk=B5e4+^!b`t%tH!FhkJJQ*elNe9#;1H#d)x0IVazpiy;okQ1-CIpbs4rySX zKCPJ4VH(je&Cl?APFqPV`GZunwMivlG$DU(${r~(kO45YBOnhc9w~<$w3cME+89X) znKy}FZoIiV<=SM#wQ7;V{U8Rj`%?{8MiQcF2VrQb^Df1MDD1b=iqHq853Tl7g8l3n0mZ}-WN-vv4M-uUDK7cX{*G`#qL$MX`@x*{f5`ezN=#R4LbP0C3l<3$_WX>UiV&}v!fzm5ND=>AW#$byxOYoU0NvW(iV&-uPMwO#=Byea5sYBv%KU`C zXo)#m5Mud_;>g2%ig_kz&+ZE8j}n4uA{NJn#-mp@l{T)WaM4tNW<1mZ4kW#~;i}J- z62gM9S&e#>70RX?BLn7|hdyxbx!lAhj9x+jp4J?)(-IO=@O##%Mv^Z15tn245K^N@ zYDA4{6e&_pLIg=@&+p>U2=SCVybn!DTHT2EMkkmjX-M2UI6zD`#Fq#uY0L3ov66F?Hou(#cxjK|AZ6_7HCa+}gjh)( zH-!LHkHjulE{|bwEEbNcQL#QPM($ct1xeu93H=FxEMo4FvL%EZ0VggEN*&DMZ}u`r zs_CwfvjQ30TR;lJ=!t#eSowVr&PEQ9!eJ@gvfJla+frwglML!RgctO zu&wKI9VH_}Z>#O-u0$UR(X<0I10mUW*^G}@!q zG5Hiiq(gdgjgsWB(f*5WYiUQk*=Q}1lE>!|BBlCgJ4n(reaq@-Un1puuQWnj<>Dgw zZ9Ca&$Jws#ZaiqPZOOF0hLC@S1Tr1V3G7<^VSR>&g;_5l1jh`(y z+G56Q;L=M=moPjMV%6$&x;S^2ALMUUIYer5w*@Ifaylw_;oSkO=@i!liw4D}FyX zjqWTw?wMby#j}JIYti&~?MPTlm~v})lSONPv46|+Ner*RSZj*DQ0uvc6ikz+6yezb zbF{FvR0vA*5^0YynDM+V>outw9_k0#tR`qJ>-CZl=UELCrNu$(exChp&$m65i6dHq z11DJ(n++{O;zJ=t)~6&a0Ia0W3cI)WuR+K*qVrTH_Gn3L!8LoFy@UWp{Kf~S#cCqn z172^FC9UT%gTI-bytNkgb zCFv^}@k2J#e+|eoYg&0Bz4qu?jb$D^4&Hi}UBBtM+l1MEJAd+Y9ybF5CwsyAw}ZResby8tUa}@s=K~5lLdI% z8%!yB&ZU6uP07*qo IM6N<$g8!e)_y7O^ literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Sleet.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Sleet.png new file mode 100644 index 0000000000000000000000000000000000000000..e31a043f163f43bc80727f0fad650fd074ca1de8 GIT binary patch literal 2139 zcmV-h2&DIkP)-n2w&}L^HES`l0GaF%EI<|@lTl!@wIb;GC~Tgx_h~%z(fV-`%*OCjsG_r?ZN*SpoT6 zM7|Ock65Y&>st|dRy%mFakBve06*@)6&n2zU!RD`-+K|bbl#Z&0gPWnzF zS2v~H8;tO-UZ5}^z#w*i=z+>eKrHUS3@ugOrS!lG`>k}4(Z7pNGYSy&0uErR9jRDz z21O}ea0`xRwSE}|2(p)eVX8geL2qb;MRY+#%knA(1u+YUSAjALkiV2T6>_*Ws#{9H zEte3gNBnFFiipF=AO(tSRLmtM{Jy}T==AvXh-z7 z^dawmQX;zc2E_6;w#350LY|+o!6}+qWCbESar z!ceS6JSu0(#tXv(X3Xo}Q0^(;#B~_GfIxUkbMQ_}K!}NdWQ=Mg=$amJDRvJaJ!+&z z#HdDrqWL6PkeK%TuQm%1Pq@RoX+qNGLc9~5pr6JeVd>BTV3H=j21rR+j)z7bPV~%k zhCVq!*n=8)Oc4q&$fRkOQi>>~Ttldtak0mW&rw?Zb_T+0YlIG(#~zPKf|3Fx=hQJN z0Kj@UcBycAFoQ#|@T@VanuEdKG5s-sa=<(QWeW&C0!mzKggWTMbLKEd4WVns01AiE zT?-Zik_!eRdO-f@1X2wlW*Xzko7_8%F(8(x+N(yYlyKIenb~m2l^xxO=))$gjUuK% zc?J=6RzNs-xq^y2E(w5G2^Lojru3*+_CGTqY}s1>U1$kFtbo|4v??(#bk(+MqZE)( ziaL|tvkw1b0I`bJTp{Di)296&Tze?%h5Iz5OT4!{ z0C4*Zh6x8(^Y>m@fVjfNz1ZS5k0(k{`^pjf(blSE7GDC$zsjhitt(5H)q)U@t1j>C z@$$_as_2~w5Y~+B&y{G_& ze^K>q9vT_TDYU9200Xq+JVlErNsSE_5kSOds|S!UU#R%N=0EzXwYL@;QN^C_6KJWz zfZY9#n1F0HWcIvfB?S{X4#VO~%~t{l>kOgz-21!-%8D9*cLdL&(p-IYVz*T^*42Bi(t11xROtwobPI zX{BK2@e7d71Z|ye0n$pr&f^y#oeA1H-2$YQf}O`NKspn&b-D#eD+N1`{|{B+r~wfj R>Yo4r002ovPDHLkV1ldQ*17-y literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Snow Storm.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Snow Storm.png new file mode 100644 index 0000000000000000000000000000000000000000..b44ca008fb1728d78de3106ab2fcaeae905070d3 GIT binary patch literal 1717 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 KMNUMnLSTZGu|paF literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Storm.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Storm.png new file mode 100644 index 0000000000000000000000000000000000000000..aa34340d058e15ebc2c2881cb96472c7d0b7ca7f GIT binary patch literal 1929 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 literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Temperature Outside.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Temperature Outside.png new file mode 100644 index 0000000000000000000000000000000000000000..9403a1c6ee05ca3d8ee1d176ae2f28154ac00ada GIT binary patch literal 1318 zcmV+>1=;$EP)L0`0+P%E z$%Z2j5s+jSNH!dK$PR%#HM7rV_E)lJPdS{C9&*pj-k8~=25-TO zUI*H2zG@F3Xarh;X4I6wkKV%n-Io?1cm*JcqIwjGzFGAPs%K_~0dI=-9GEX=cE?E! zP5EQbqF>`7=)_B>fj=B|1#oZ8?18f#Q5ax$C;Bx&5Ml)URQc}+;%0bDTY!2zW|yKr z0titPhR2|D1@XsQ9y+~+5E*aTh3NML@{gJQ5-=RW0AM`c0=p?hUIOjpo4Z;MAc!`` zLgb?bZJ{kYdrv`A*iddZFV+fV675#;WiJEJi0A`mbKX)5grx~_?wynJ1PqfWZBq1W zfRLxcBSy{68qwcOUaSU)XRYs12QOq9i-I}NMj+GlW%lDS z9?@s%n$r8XH~k&Iyk;Pi=%X!99M4J>@?mI8?M{Cwsmik0x;Z{P!rFn`_kjJ2wZ&91wW8%N~LJ+>jI%5ckx&UUA8Aye?=tB_kl6fwV?L z0wN%l7D(1?RCv17FXsv7f&`*3{@i76qCRTLYVG$Dn1HzF?xEr+&l8Xshs)XmlFV?5 zvIL~k0?C?$NyMPodB_PhJbgr;hKm=sg0<9akrHQrlxdiV> zLa%n^A)r1jN(q6(=2nzMNXrnOfGKSLzeiaeT6F^PM4IZ zI}KG3b$LkTMzmFYqn@rMYjAifAZE6PT-MUrUd|AQ&JjyP`e;b&QmB1Mj6-oBvN|9k zx4mI3HeJzkxT8`WqxwC&hg43;>SiMhcj^!~$;FzREWUfdb7@GmWh)!@2Ey@EE^9k= zKUg@#oqIL`DHG=+13qu?T-Mfdkozza0Vx9^IT-m){(ia3GqNNEaz7tNGUbY#x@X;vGxu3E+Ao(jcu?=AVe_Hk1)rY+28xp&2Ro5 z2G^{KvIY-n-`xvHGX4T0AjvF{Y&h}|0ZC?oWW$k%2uLyuBpZ%AL_m^RAlY!_Ap(-j c0?CH+4P(embU^=7ga7~l07*qoM6N<$f|vAMH2?qr literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Thermometer Automation.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Thermometer Automation.png new file mode 100644 index 0000000000000000000000000000000000000000..c20b1f797c9026c99a7c107bf756f1cf7351012d GIT binary patch literal 1728 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 X($*ztca%HrDHpIbyI@*s>=N}Kk+G0V literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Wet.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Wet.png new file mode 100644 index 0000000000000000000000000000000000000000..2e3c45c20f0d5d03d4427a5fad7ec79854894633 GIT binary patch literal 1806 zcmV+p2l4ocP)CrMBWsUUmEmu+NE~}1Rwx}0T_Vde%uw1*F@xJ z5y51I@wte6<{go{0`h~1yq!?~J0kLn?y0P5l-{RXJ>2MqPISgiQRS90Jk*ICgRq z9KD-y2SDD~at=+Ye~8Gd%Aenf$TK%+h}@#5ZaH!yD%gY1cu7&bD+hmdhLHRLNNT_g z*n?>zL;qBnN1_NQF2>aXp*(`pQ{zJs`DXVAzCtryZdh_eG~)pM%EPpp@2wMo*EWA z!hDNe&$pKEw2149fLP`A(r8KZC4|VYOheR|g#bYcGAm2Kb>@T=yWWwKJa!_gM1m8tXc zfCAVle?pYT_RTszf&Aix=bSpDv!rYqM&2Mhv-eZQP!Q0twb3)sQ`Q+w>A0kQIi zK;kj7%xgviVs-R_U`I_Cs~Lv%0A;$V3d$G>h~<3aRdUpH z!9Yw?3n+j=!LlZY>CTMNfaDx+>V<0ah;R>>f+J6b!a2oF%{fxSjbcdY9^1W4tWffZ zqboHWT`OS=tboB&9r#&*SdN@X1|?{#xyOoyF@O_CR3Y-h#2p1a$GGPIM=(SyNgynd z44JmJmx?*L7HsoNSKNST?o{x417ejV_6;N}k8l(5Y)K^5-_uU<_5_606pDwbMYwOT z=JE&+EZMh;YkMsfBz$pdPe3eoq&6Q|z46&BiBDpkcAlgsAeQgYR=l;nb0$ktQDTpP zBg>p#fLQFXUc}mLFpDJ?bBCL*UVvyN62e^QZ$&B=OKQ7-*%g?XkUMKK+;sH-q;=!j zQFgT|KXrXcLOaxS^#DZcP1ocU8cS-rfUN*orYgSoFw@lokUy1%Psz5<@S;=g_GVV& zPjOfP4>Mh@fLJ!SrZ-Jq0lHK>MVL*!}&#PT1t4q4m0Fw|ym2Yakijs{X| zF*JGKRzS3{^~k1WZ3FaZK&&Pj&t}nShkUw!rlS=Qiy^i5o&ksz;c;j*Z0rLxZFEgw zYn2uYb#)(NRTuWPH>>;EHGypf1c0<%xD;!m{w#L@9#aW7}^66D-S7&L@bsC zvr!ZMl+LZKy;c{z|$|roEg#WdTYoi>xrCiHV4=;xH0E8839XAeU zEo@u^7@Q>$T57X%SmFCGF_f#?a<#YN#n4`WpjhjBBBhGj&#Or+Ywm9`x+IL% zSkfgg=>-T1u~tuw!k9bCRB`W?Bh_4QnY$97Y3iaUAUR=6K`B|KrT2>GStXhp$E>lW zxyIES5EKwjNNFE>(Ugh(CKTO&Fy^S@wd*VvmmaC+-d31iTQYh<))9b&2Ou;GF5S3x z#&%9kk+tVStWdoM*#9k@k${AUu_|$-@y0c1Pjq(X#x-sGQBA8Lyq9*g&OIQ#%}&ex zdY-&pfV3d7U8@07+nKaBlP`u;0QJyLy+Ti?O|`<_(va2qoO#XnR+2A$hEqRH+l3FZ z62sgnUcjK;tDRMJmlzi6Wa_kBF%*A-uOadZ1yO+Ds}F?cS|K!72P=B%M`TE@e6m*@ zfM@{33O;%Q?6kzNXhlq#gp%M-!wR7bkpI+8Bn2=ekD716Ji#b_T})Jr_5vjBVgV;^ zFB1d|0bwt~0%TH{r#*H7vH)?W0cYYYhAcpwX~3B{iy;dTXBu!O&SJ;{#F+-1iL)58 w0CA=PXW}e|EI^!Tz?nFUAqx;^8gM4gzXYgpbkDR5rT_o{07*qoM6N<$f~;mw#{d8T literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/Winter.png b/mdot/mdot_server/mdot_server/app/gfx/icons/Winter.png new file mode 100644 index 0000000000000000000000000000000000000000..49082b0e02cb33e936777b877780eaf0a7d3ceab GIT binary patch literal 2250 zcmV;*2sQVKP)01+SpL_mF4+gDTb=C8YF_VudWs#jN6 zZ)dl=zv-Xpo!$2&-A5=3JP9SuElj$B1e*jmkQ+!a3j`DA_K+J$Fbf0|=k|~rNH7Zo z6X)t4@>#>4-=&oP2xjXkajp*J--ed&q?CS|vOuttZXh=hlLg*5LeSsE=vfbWIi>Vk zO6gbA-A^2J1rGtnvjYgBD2Flw1Q?752;)OTi4H_yU{nr_nL`-?5g1&D1DK(qLg$9JVRi}_|Q z@mosi?IItYn7Z4yiV6gYXP{V&7#0S~LF1q7qD7HyxVl)iF!$xKdJ0fYN|ek?FcasN5W za;F*(hwlQyomjZl7IwHh9^^fG&{sVV`K7V=T&2SU8+d_W6omdZrSx?XSMh?6D^{nM z^op0pF@Drs^xQ_{<(x~ahKc6Mk?w_I?$YE1{?Fr6jx*x#P9VKJnCFiVju0%Z8dpg6 zcnDR~@0BS?74pSVjkFBL?}6t%b^>X6xa1G|XkQ)^FV}+zfR~gH)24Lw0HKQN-H_kJa z_g14YJ8wY>*iHJQmRc$TLN;Vye~!EjN)ysEG; z3P_o(81~}S9Y9z+X*vmi9w5}=siv?eWR=&$Q*d)_Ig6)IyIT}m34}t0yiu#HT9bva zguZyklI=wvAbB?z@6ftl2O3uK88)PiCj4OeTzx zUp$+w$rHVHM`rGpWvB(pE zHg{t!H`R=Z3`F!GzmRA(Wpd31>=eN(G_4tpEti~o1t58T0nBWfEaR4TW0zRHbCIh7 z(Uh^Gc3vj$wx|30R{*lA8%qMG4RePqEC-opz--uW2bXmA480feR-OW3LH9p+Z7z%^wu z)f@R`MeD?66Aut+E|MgryNe;TN&$lKG24yJ+a0}bFLG#h!^rux`85Y}1E0Q{yqNST z%|(pJGlue@FO&mnDTe}#pM7dqYj@1F-?h78W}a5&0BR4S9;N+0yP1qQ&AGBO0|2Zi zX7fa^-7y1%31MmTBR6e+0AchT!pMUjiki*w%UAt9S@LFP~tOyC}TBw!m~+v z1&})rI4w=8YLtN=o|Vm+bV7-rr~ zwi$?2N!sW7OWH6VAcQ6D=Cgc;t$6Wshle0z>xIvmeBx@uSb^Flaj0FYMz1B43Iww}9qlY^%NE`r5$>Nu67?K0G7Kh1PCMykEY=J?l+N zfRsX)yE}Se&GZg;MZ29I(rXXp;izoGxQZ2zhsY`y*Cu(DFG{v%7~p1G?xPvD6A1Ti zy#rG-Iw6cO<@)@r7f8=wtxp@7<7;uVGd|DM%9G}9?r4VX0@5><`Qc5bO!-asQqS@m z@gqC5e&2cs$N8pi?nsbbKzg4x@+vZdAv&*s();Ggii!1r&n_U`sP-C|w_P#|VDz?@`B>G9c*Q{5R#MThp9Tyb{6&WRF%c%0@>fWC` zqIJ^)M)hQ^__n~{qEUe$TMJ758S&8{1*`qpB)lgijOajWP|9z*kD7~wz8p$u7*_z2 zLt$lHc2Y+`7%xzya}X{}gEG0Qi~s-t07*qoM6N<$f*M^OOaK4? literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/air-conditioner.png b/mdot/mdot_server/mdot_server/app/gfx/icons/air-conditioner.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dcb353d4961fd63a47d4f7c730cf84e313e363 GIT binary patch literal 1591 zcmah~`#aMM9A1*mEgM}(%y+gVm$`M0OfGAUMLEbAS!9IS+0Zb@5GzDAQ`3?zluOu2 zjZ`jC*3Bh$l*pxQE^{UkqI8b_f`0hCpXYg>&-=^!e4h8s`QwnArrI_&5D276aL4(q zZOYGqsH`F5Jh|>5zU1bRD99 z=qHXY*GL|PH4BAuCyDJsXJzWu`L|zgt+31gWDDk9?sBlBt~;ZAbP3puCS`)VwzkH} zkdHS{BY{>ZWXGZCUlCmuryEfSx=N9UUF;8N{>Wda4?x%su@-cnV-9mMxqdAZUqDL-NG}g_DjaRk`*4mxci;&i4r<7;US7pyOVyXvIlC3dF z$O;)Z?ECbabnbiC*cO08y+(9EHjB$I!S;DpClsiuXLeV}s3YXwEK6*vw=NMgNV~ms z+(^WEPYb?d_33R{PcQT=x6JpUbASR-xn&ayc=R|ek&BcXjn;)0aFIw|rPike%{99K zsOOb`en|w|adxMsl46wm{bctoi!56Pk5M$$Pa>aUBPS;IaUuuLV_v1c{9qp#XdB*% z-orS(H0|3K`~9X<%a!FOV*=HyxYWGG0R7DrHF|`&0J+GF^Ttdv4qQmMd_nH4JA&Yp z?z*C=+1$5r#;*4H6VZ1xSjg(BYDaMJ78c%qXq&)-aH?RXEFsB`<4}oWYiy)u6+-17 z(nV%5m8icV)F`kUgEee!Sg;>lllgYagY5dgcjH3(0uMj~d_MOcV|PBybt zOj?up{7rzpf>wOS#I#q)ywQs+y|TR=E)VoK1br;c1vxvA^M zXBrv@Zk%F!=HX7T3Ts&pWN|uC>?c)B-4se*TBDAyT#(;a@uI|lzLma2^@mi#N)!en z(3{7-o}c+)Nk(74mF(s7TmG$jmURJd0saJ=<3nPLZY#Zq0HXE?p4GX?Gk8d9`lH$D zId|NwW?e>ob5rtcW2nSUtZPk*R9Oz1S35z&mU3QiUDTxkZSv&~JasCBeYWdiO?&P- zQg}*2pwje2ERSCA7~Jjt`ij6^$T1LzoAPOI3Ro6(h`O zHNk4~hRvFx8wPeoiX{h7%$7kpBX`10C$2O2>zn%lj`MOSzlIH?M7UvVjgyciWH*;y z)UbT^1Xokw%d;{2Ql@1=5XD`ij#KORUgi!A1ei(4UKJ5@$(~&fl27EnY+y6h3_BoO z-BgA-M;U4&S<+YHmV<*LDqVev`Ueuuix=@x#oYTd;abj~k+~10XzCSMHaY z zuD(1#XStGUgNv-EWqnQoES(+d4F0q`WxTrKoC8z)g=`MPURXg;+5{5+ccsqKL7v+s z^J!Ys)C9rZYNddyZ>&5K=!EPrUA}tC8GZP;-dKCe@#yDu9%F{sE*tTy2VF=`8Zm&r z3AWn!!F7N%VIJmbA{|ipX~EZS)8dOOfjTN9vn-AZZ@iDx+Na4Nx z&QkWdEFHdMmzCI(V+E-ym(lf%j)@m1N#aX};jH1=>U-FbGA+U#@Y;*0xD>rZstR&u zTt*1bL6NpaNWiwoU=pLM2ckt3ASpW@u4kJ7>#ujl@Hic~#Ot4s6p%=8kjE8FZv3)} Y2A2^}l;GQv)(Qbc*nbEo#D--24_Ct6egFUf literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/av-receiver.png b/mdot/mdot_server/mdot_server/app/gfx/icons/av-receiver.png new file mode 100644 index 0000000000000000000000000000000000000000..362b9dfd178ffdaec943a28c1c17d25e46a3480c GIT binary patch literal 1408 zcmaKse>l?#9LK*KTQjX=hWxr`*m5Q}QAl~7wfxvBJGPbB`SIMdD~jlrChSZWxjNB8 zBR`6Z7H=OzJz@QsDel(8`01$t&&pvu$_+0U-2C>8FVQC|n&V>hpa0G}5FfIE!#FwyM zdgFs9?b&gz^;48JWqs%P@*I;t7&C8BT|phewR_I=>pP%<$;3ZFd6LR-bNz zbgVua!P@RzfajsV125w}Gi(exH~??XnYaG_xxJ4`nl{mAf;IZ%{th>T`EaoE7)=_jAb}f?K#RghW zXB2EEY_%zQN{#W$IC&72I9dzp$dlaHeX!ul$JLZ>Ea5!(x$sv#l7mwciSe7qD4h(YNb!TX{TJA;$12)Bbc?S~w^i8&ieju?L zqnA^nP!%fD9P*GQxK5zLU;m0oyAUI!s%TgXF3Hd(ds(WF1~v5K`iWOKnh{ojozmh) zJ}wKYF2dDqb2v$L3>|t##r6`CXjrqHU1F4YUM#*Eg;t7@h8jvTHa{$j5XR@6|_j{NwXOA=p`(aC*skApmtU~&Ud zMo!e(B^u-yA_Ut+O9PLhPUMGx1VVXz@z>1Zy5Kb{W<7)BL4qC0x(~aD!i%J(Kw=90 z&iwFT6(A~Td1GP=X?MoMFGkcj=0ljjJzn$sk8cvLtL6)X4&^c__BYNogyS>821DID z{n>S<({6XcNc~E#z5#w0g8=UkfYmBliS7C@cDmHIt3c837^kgl+7HQ8?0fr`KOy0d zyL&K$B1_B~Z`i8>PU^7V6@PTM_bwk&{(Y)=?fYTjf&{hVG$+$p=k#ahX`e1ep`~Ff z+Ga+Pp52^Ru6va)IG2*pbE@nKDA!#?W~|$%kr)>~>rUDXwIA0`a^>!#==}tY5nN~a zlj6ylB0Ux5J)b+FM>%^m`Lqdwx2E2-(wcI)+U9Tz8J$^JdrVTr#gtPCaFUQBPcE~o z*btLtteSqcke?*DK`W9T5=XjXviOYx~CMxOr% DD*}kO literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/bright-moon.png b/mdot/mdot_server/mdot_server/app/gfx/icons/bright-moon.png new file mode 100644 index 0000000000000000000000000000000000000000..4f1b2287a53e594eccf5eb5c1b452dbbc73251c3 GIT binary patch literal 1743 zcmai#`8V5%8pgkgt3RLX+48G zgPcJQGANnkZ~v`RHX0SX{`vhIwj`6ObZws#V^J=8H|3S9TW1_GoNuf_mxhw5aLS>p zMV!SF?14xYh`f+Y`+tD$&dbz{a$FtvAm06`9Av6B|X z3BM8;4f1oP=B~+Q^+VLd&Qa*W5mEQ_vvf4S#E!KmDrTGJ3ffu%z^NCj++e)xno-u6 zeWmP!D;HWZ@EFXZs7IlXUDBB-8rT9fjV?cU{7Fu;TWia!C-A@nbLNsoVu76`R09Ao z^|l`}_K_tPTZ7UVfsSP#VtL-fnL02ySA%l^9R4!J}%HB6npe z@HX;ChunDXY$(11?{glNa8hv@-J3Cr4q(dcjB-=f;^n}Ut2#s*96wz1%T&WMc7j5N z(|t)z4+Ac}@=8B~&(DZIN4>kS20H?s-fnEug&Y0}>cV8kl^ao~Iqm4TE^s;uxzQ_< zR%9!@X=64B1R?_Z1s@IQ2O}y=pOUz?R=B+ZI&aCh*VacduC0 zk4$kHM4`X$3b#fUjc5Kkoei78Ikl}6f92WV#`QD)<(7Kt@0T(0oQa?7Cx88G@>UF! zmgoDLE`u^^oU@A9zZ%)^Pdu8;Va>V2_&%OJdI-*)JFC7D>o_~rQl|smd@?dTZ%#Sr z1-Ei$_6cGOPfT5|v%UTL1+Ho5$jER+#tnGrDWXg=>CtSpN`Fn%0D?KGb*%Teo18ix zK(yxEpbK*Hq4SZRFK6a#2=<5shVMgXH9$9yxVN`jvJo0VqXo{4AYwLyQ~HF20SLUB zUwo}DqcGylPqLZ}GZms^{o;l@1yU%cU@- z1TXVXWgbC>@+~k_lgZiKPNe1YPX?A{1bno&yAlCP3f?`K{mR;}1s42GGhOH&17+Ca z-o4Vpi+8C;?7p*|L=1kQ)L8UB;6yZ~dL!p0=!><6^$|pY)^MJ(IJk$PV7Pt>9Kh{s zk*Nr)Kd#%lDPlq!BFTQ(R_hp#@5e#mUs>7^)-GM&psEQx8{NHl3urF18^2~!%op1h zaaV2I7#_lXtQdxZf?C?~7kmj(y+23Zvabt+Xt2OKe^1Wp$?Xi77LlwRDY+ zcH`$_KW%1$@pl43kOoR4Y~n15l{T@M{Z??gPU5M-G(i@Idbg?B2i<9%!6Tg)LW{*3 z)POa@MkDSjXDN37jit2Z^lilO<*eoz^A6ydr$Znlovi8Bju;wZkV~4A+}dlZ{urxD zCtFxO>q5Q#uq~2FT>|dQ=_;#Ot5%$Z)Aa_uOdTcL%dkFhWzg}WwPYPQr_~{+97%d} z-DFn;O8=$2TI>&L)O)A#mhBr=;N*VJ?A|Y8veXb{c(1E z-GHB^^dX0`__cWt6KB4{-NU|LA&=B{4v%=6L)n@g7AmNYEHj=W>hLAYn#Y3IRwk1%ib`g#g4pnAwYr z4nNK8$0B`Rn%Vn;?@!8@R#Zq5{Y@sxl=w$w@>jmzn%Vb)Z>dI7Xa5og$iY$93*@<( zy{bH_znIzUOrNi2mi|_>6i00NNv3LKq#SH0V~AN3fEG$ENLS8rR`+ukv0?>7oSf-wUKK>jPh`w*@n!Rlcn zAkx(u3ow;d&xE~(^iInx(74Ja4~A88%{K6}Hk+pqLfV68jr6)k9$l5;W zX@I1!U2|XVek**1nY;(81!ieGq}!G%C-(_MvQ2$*t+acP!bfeThpiA-U>g_#Bp4)s z0OY;`Ef>T4qwZlrg#_bt8X$^AY_&dGSf2(+Z6YnF#abT#+3}(6Cgv&7nagUajY}VZ zWVBnk;}Adqa=)Av7hHvp`&kQ!BX*SA1XS3~XExDqc$fegE@|I@0O`|jcyE9Vm$Yxd zr9h4rvGt|3Z|~BAKUYS*lZ!4V82J?dh+iv-B|s!H`<(#9ua(3SAQGAVP5|Q9N@58R ziOhZ{0P$-ju>^=jX1^1F__dN)0z@LS-w8ncT1hMcB9Yne1R#E`B$fb?$n1CW2d|Po UbZ{C1^8f$<07*qoM6N<$f}O&Opa1{> literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/fan.png b/mdot/mdot_server/mdot_server/app/gfx/icons/fan.png new file mode 100644 index 0000000000000000000000000000000000000000..6d3b04af6423743bda6ca85c8a9c8b3768520813 GIT binary patch literal 1977 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 FV1k)Q_~ifq literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/icons/video-projector.png b/mdot/mdot_server/mdot_server/app/gfx/icons/video-projector.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5fdbc80f44ffb26137bbc74325a7fc0a1037bd GIT binary patch literal 1155 zcmeAS@N?(olHy`uVBq!ia0vp^DIm?T+y_>C2o#PO5`Xl=)@C!Ga>@16vLF>x!r72Y%MxyjtusG@Y4+hV8Cky)RT*q@a@Kg=e?@r~oaZ9m1u zuUZbWtWZ}ro#5ozq%dLPQ^SVxUS6paJ}Wji7@FSaO4SfJc6aqbj~~H>w{M?3k$6q$ z=zY`o8Ip6>CThL%zSjP;I{NVS0EIax=CSYn&(omaTSl~qWnM3C`P`d!tJKZ+29?Pr_V3ml&R43cfU}g-J6XX zDU)+%&l5eXxz)1tvV(=-d^HD)pWoV6ZCbhfW|&ojw&x8gt|h6Lf>%vW&9QIhJz`pB z?D~J6&5YEEv)Lvc{aJfBbmzYvA`T~?E%#-9s2IIvMYNZ1^`52QW!Z#QWGmP@=Ox^A zZqZ3AylC0w9L8WY`^wIv2an#~_w>bNtMC;zvD)0`Tr-*6RBbM>Pq>>C`MJ;M2KW4L z>u&zAe)cRWH}Qn1&EZqG4sF}7@^Z6yn`r3X(x8rFAO3}!ThAW7X52HWJhynF^t3tA zn>K%2nEAevJ96@bn^BGPgDvKL+nTrkbCQc${HDE2r`&Q7+mpiAn`spOG4)~1LD^)! z6Q9mq+oQKVrDFT)GGSmunTg4MG3Y(R_w#1wiVbxoA9K!HN2xu#rX16C(%1dp{A=Pj zA71;jcWt`1bK{nhn4Ns=j#IYvZ}_P(UB*qK?v2?wCNJ%ttVtW6-hRLKVRq(+Ep00+ zt@$E5SIwDY*_nQPx3|Fz-;b5?sr+#7Ad6;7A2w8Cl-pvSKQZ9xFdDryIb1~KBH#_DsAQ4{@9jEy8Y)hM9)1g z0v>5WZ(DS$mX)p0zxMXwGoH(vF4%l)CtW%p_mzH#I?#mm+ wKH}%YwGVIk^!{5{qdB^9q-935ynN1nl2xM9qm&>^VBx~x>FVdQ&MBb@05FRTJ^%m! literal 0 HcmV?d00001 diff --git a/mdot/mdot_server/mdot_server/app/gfx/light-bulb-vector-png-light-bulb-10.svg b/mdot/mdot_server/mdot_server/app/gfx/light-bulb-vector-png-light-bulb-10.svg new file mode 100644 index 0000000..e842841 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/gfx/light-bulb-vector-png-light-bulb-10.svg @@ -0,0 +1,16 @@ + + + + + + diff --git a/mdot/mdot_server/mdot_server/app/gfx/projector.gif b/mdot/mdot_server/mdot_server/app/gfx/projector.gif new file mode 100644 index 0000000000000000000000000000000000000000..f9b7180bad1da7913691d9138a1cbd52899d904d GIT binary patch literal 2023 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 + + + + + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+
+
+
+ + +
+
+ + +
+
+
+
12:34
+
+
+
14 April
2016
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+ + +
+
+ +
+
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mdot/mdot_server/mdot_server/app/js/mdot.js b/mdot/mdot_server/mdot_server/app/js/mdot.js new file mode 100644 index 0000000..0bceefe --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/js/mdot.js @@ -0,0 +1,412 @@ +'use strict'; +/* global Backbone, _, $ */ +/* global mainview */ +/* jshint browser: true , devel: true*/ + + +(function($) { + + var mqttConfig = { + orgId: 'qz0da4', + userName: 'a-qz0da4-dfwwdkmkzr', + appKey: '9txJEf3Cjy7hkSOvkv', + prefix: 'iot-2/type/mDot/id/' + }; + + var sendAuthentication = function(xhr) { + var user = 'a-qz0da4-dfwwdkmkzr'; // Your actual username + var pass = '9txJEf3Cjy7hkSOvkv'; // Your actual password + var token = user.concat(':', pass); + xhr.setRequestHeader('Authorization', ('Basic '.concat(btoa(token)))); + + console.log('Auth:', ('Basic '.concat(btoa(token)))); + }; + + var EventsModel = Backbone.Model.extend({ + initialize: function() { + _.bindAll(this, 'processAdded'); + this.on('all',function(d) { + console.log('model:all',d); + this.temporal = {low: 0,high: 0}; + }); + + this.on('add',function() { + this.processAdded(); + }); + + }, + processAdded: function() { + console.log('Model:ProcessAdded'); + + var tempCollection = new Backbone.Collection(); + + _.invoke(DeviceCollection.toArray(), 'destroy'); + + + this.temporal = {low: 0,high: 0}; + + _(this.get('events')).each(function(i) { + i.evt.decoded = this.decoder(i.evt.data); + i.evt.dateTime = this.dateTime(i.timestamp.$date); + + if (this.temporal.low === 0 || this.temporal.low > i.timestamp.$date) { + this.temporal.low = i.timestamp.$date; + } + + if (this.temporal.high === 0 || this.temporal.high < i.timestamp.$date) { + this.temporal.high = i.timestamp.$date; + } + + tempCollection.add({dt: i.evt.dateTime.dateTime,lux: i.evt.decoded.light, temp: i.evt.decoded.temp, co2: i.evt.decoded.co2, humid: i.evt.decoded.humid, noise: i.evt.decoded.noise}); + }, this); + + DeviceCollection.temporal = this.temporal; + + DeviceCollection.models = tempCollection.models; + DeviceCollection.trigger('update'); + console.log('temporal:', this.temporal); + }, + decoder: function(data) { + var _obj = {}; + var _data = window.atob(data).split(''); + + var bytes = _data.map(i => i.charCodeAt()); + + _obj.light = parseInt('0x' + ('0' + bytes[0]).substr(-2) + ('0' + bytes[1]).substr(-2)); + _obj.co2 = parseInt(_data[2] + _data[3] + _data[4] + _data[5] + _data[6], 10); + _obj.temp = (parseInt(_data[7] + _data[8] + _data[9] + _data[10] + _data[11], 10) - 1000) / 10; + _obj.humid = (parseInt(_data[12] + _data[13] + _data[14] + _data[15] + _data[16], 10) / 10); + _obj.noise = parseInt('0x' + ('0' + bytes[17]).substr(-2) + ('0' + bytes[18]).substr(-2)); + _obj.binData = bytes; + return _obj; + }, + dateTime: function($date) { + var dateTime = new Date.create($date); + var date = dateTime.format('{yyyy}-{MM}-{dd}'); + var time = dateTime.format('{HH}:{mm}:{ss}'); + return {dateTime: dateTime.format('{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'), date: date, time: time}; + } + }); + + var mDotCollection = Backbone.Collection.extend({ + model: EventsModel, + url: 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/', + initialize: function() { + this.on('all',function(d) { + console.log('Collection:all',d); + + }); + this.on('update', function() { + // Console.log('Collection:update',this); + }); + } + + }); + + var ItemView = Backbone.View.extend({ + tagName: 'div', className: 'item mui-container', initialize: function() { + this.template = _.template($('#item-template').html()); + console.log('ItemView:Init'); + // This.render(); + }, render: function() { + console.log('ItemView:Render'); + _(this.model.events).each(function(i) { + this.$el.append(this.template({item: i})); + }, this); + + return this; + } + }); + + + + var MDOT = Backbone.View.extend({ + model: EventsModel, el: $('#output'), + + events: { + 'click button#refresh': 'refresh' + }, initialize: function() { + _.bindAll(this, 'render', 'refresh', 'update'); + this.collection.bind('change reset add remove', this.render, this); + + this.template = _.template($('#list-template').html()); + this.render(); + }, refresh: function() { + + }, update: function() { + console.log('MDOT:update'); + this.collection.each(function(model) { + + // Var events = model.get('events'); + // var e = new ItemView({model: model.toJSON()}); + }); + + }, render: function() { + console.log('MDOT:render'); + var that = this; + this.$el.empty(); + this.collection.each(function(model) { + var events = model.get('events'); + var e = new ItemView({model: model.toJSON()}).render().el; + + console.log('render:done:'); + that.$el.append(e); + + }); + console.log('bah'); + return this; + } + }); + + + var MainModel = Backbone.Model.extend({}); + + var MainView = Backbone.View.extend({ + el: $('#main'), + template: _.template($('#main-template').html()), + events: { + 'change select#device': 'changeDevice', + 'click button#refresh': 'updateDevice', + 'change input#from': 'changeDate', + 'change input#to': 'changeDate', + submit: function(event) {} + + }, + initialize: function() { + _.bindAll(this, 'render','changeDevice', 'updateDevice'); + + this.model.on('change',this.updateDevice); + console.log('MainView:', this); + this.render(); + }, + render: function() { + $(this.el).html(this.template()); + return this; + },changeDate: function(elm) { + console.log('ChangeDate', elm); + + if (Number.isNaN(elm.currentTarget.valueAsNumber)) { + this.model.unset(elm.currentTarget.id); + } else { + this.model.set(elm.currentTarget.id, elm.currentTarget.valueAsNumber); + } + + + }, + changeDevice: function() { + var newDevice; + console.log('MainView:ChangeDevice'); + newDevice = this.$el.find('#device')[0].value; + + this.model.set('device', newDevice); + }, + updateDevice: function() { + var fetchObj = {beforeSend: sendAuthentication}; + var rangeObj = {start: null, end: null}; + console.log('MainView:Updatedevice'); + console.log(this.model); + if (this.model.has('from') && this.model.has('to')) { + rangeObj.start = this.model.get('from'); + rangeObj.end = this.model.get('to'); + fetchObj.data = $.param(rangeObj); + console.log(fetchObj.data); + } + if (this.model.has('device')) { + // FetchObj.data = $.param({key:'"'+ this.model.get('device') + '"'}); + // this.collection.url = 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/' + this.model.get('device'); + this.collection.url = '/api/mdot/' + this.model.get('device'); + // this.collection.url = 'http://127.0.0.1:5984/mdot/_design/getDevice/_view/getDevice'; + this.collection.fetch(fetchObj); + } else { + console.error('Nothing to get!'); + } + + } + + }); + + var GraphView = Backbone.View.extend({ + el: $('#graph'), + template: _.template($('#graph-template').html()), + initialize: function() { + this.modes = ['','lux','temp','co2','humid','noise']; + this.mode = 0; + this.xmlns = 'http://www.w3.org/2000/svg'; + + console.log('GraphView!'); + _.bindAll(this, 'render', 'changeMode', 'updateGraph'); + this.collection.on('update',function(d) { + if (this.mode > 0) { + this.updateGraph(); + } + }, this); + + this.render(); + }, + events: { + 'change select#displaymode': 'changeMode' + }, + render: function() { + $(this.el).html(this.template()); + this.$line = $(this.el).find('#line'); + this.$maxY = $(this.el).find('#maxY'); + this.$datapoints = $(this.el).find('#datapoints'); + this.$baseline = $(this.el).find('#baseline'); + + return this; + }, + changeMode: function() { + this.mode = this.$el.find('#displaymode')[0].value; + this.updateGraph(); + console.log('new mode:', this.mode); + + }, + updateGraph: function() { + + var calcArray; + var startX; + var xstep; + var scale; + let ceiling, ceilingLimit; + let points = []; + let data = []; + let circle, title; + let getMode = this.modes[this.mode]; + var occupied; + + _(this.collection.models).each(function(i) { + // Console.log(i); + points.push(i.get(getMode)); + data.push(i.get('dt') + ' / ' + i.get(getMode)); + }, this); + + ceiling = points.reduce(function(p, v) { + return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v)); + }); + + ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 10) * 10); + if (ceilingLimit > 1000) { + ceilingLimit = (Math.ceil((Math.round(ceiling) + 1) / 50) * 50); + } + + this.$datapoints.empty(); + this.$baseline.empty(); + + scale = 124 / ceilingLimit; + xstep = 234 / points.length; + console.log('Points length:', points.length); + console.log(xstep); + //xstep = 2.34; + startX = 46 ; + if (points.length < 100) + { + startX = 46 + (100 - points.length) * xstep; + } + calcArray = []; + + for (var x = 0;x < points.length;x++) { + calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (136 - ((points[x]) * scale)).toFixed(2)); + + title = document.createElementNS(this.xmlns,'title'); + + if (parseInt(this.mode) === 5) { + occupied = (points[x] > 920) ? 'purple' : 'red'; + } else if (parseInt(this.mode) === 3) { + occupied = (points[x] > 579) ? 'purple' : 'red'; + } else { + occupied = 'red'; + } + if (occupied !== 'red') + { + circle = document.createElementNS(this.xmlns,'circle'); + circle.setAttributeNS(null,'fill',occupied); + circle.setAttributeNS(null,'cx',(startX + (x * xstep)).toFixed(2).toString()); + circle.setAttributeNS(null,'cy',(136 - ((points[x]) * scale)).toFixed(2).toString()); + circle.setAttributeNS(null,'r','2'); + circle.setAttributeNS(null,'stroke-width','1'); + + title.textContent = data[x]; + + circle.appendChild(title); + + this.$datapoints[0].appendChild(circle); + + } + } + + console.log('This.mode = ', this.mode); + if (parseInt(this.mode) === 3 || parseInt(this.mode) === 5) { + var avgLine = (parseInt(this.mode) === 3) ? 526 : 852; + + var bline = document.createElementNS(this.xmlns,'line'); + bline.setAttributeNS(null,'x1',46); + bline.setAttributeNS(null,'y1',(136 - (avgLine * scale)).toFixed(2).toString()); + bline.setAttributeNS(null,'x2',280); + bline.setAttributeNS(null,'y2',(136 - (avgLine * scale)).toFixed(2).toString()); + + bline.setAttributeNS(null,'stroke','#00ff00'); + bline.setAttributeNS(null,'stroke-width','1'); + + this.$baseline[0].appendChild(bline); + + + + bline = document.createElementNS(this.xmlns,'line'); + bline.setAttributeNS(null,'x1',46); + bline.setAttributeNS(null,'y1',(136 - (4884 * scale)).toFixed(2).toString()); + bline.setAttributeNS(null,'x2',280); + bline.setAttributeNS(null,'y2',(136 - (4884 * scale)).toFixed(2).toString()); + + bline.setAttributeNS(null,'stroke','#00ff55'); + bline.setAttributeNS(null,'stroke-width','1'); + this.$baseline[0].appendChild(bline); + } + + if (parseInt(this.mode) === 3) { + var bline = document.createElementNS(this.xmlns,'line'); + bline.setAttributeNS(null,'x1',46); + bline.setAttributeNS(null,'y1',(136 - (632 * scale)).toFixed(2).toString()); + bline.setAttributeNS(null,'x2',280); + bline.setAttributeNS(null,'y2',(136 - (632 * scale)).toFixed(2).toString()); + + bline.setAttributeNS(null,'stroke','yellow'); + bline.setAttributeNS(null,'stroke-width','1'); + + this.$baseline[0].appendChild(bline); + + var bline = document.createElementNS(this.xmlns,'line'); + bline.setAttributeNS(null,'x1',46); + bline.setAttributeNS(null,'y1',(136 - (1045 * scale)).toFixed(2).toString()); + bline.setAttributeNS(null,'x2',280); + bline.setAttributeNS(null,'y2',(136 - (1045 * scale)).toFixed(2).toString()); + + bline.setAttributeNS(null,'stroke','red'); + bline.setAttributeNS(null,'stroke-width','1'); + + this.$baseline[0].appendChild(bline); + + } + + + this.$line[0].setAttribute('points',calcArray.join(' ')); + + this.$maxY[0].textContent = ceilingLimit; + + + + } + + }); + + var DeviceCollection = new Backbone.Collection; + + var mdotCollection = new mDotCollection(); + + var mainSettings = new MainModel(); + var mainview = new MainView({collection: mdotCollection, model: mainSettings}); + + var mdot = new MDOT({collection: mdotCollection}); + + var grapher = new GraphView({collection: DeviceCollection}); + +})(jQuery); diff --git a/mdot/mdot_server/mdot_server/app/lib/backbone.js b/mdot/mdot_server/mdot_server/app/lib/backbone.js new file mode 100644 index 0000000..55ccb22 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/lib/backbone.js @@ -0,0 +1,1920 @@ +// Backbone.js 1.3.3 + +// (c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(factory) { + + // Establish the root object, `window` (`self`) in the browser, or `global` on the server. + // We use `self` instead of `window` for `WebWorker` support. + var root = (typeof self == 'object' && self.self === self && self) || + (typeof global == 'object' && global.global === global && global); + + // Set up Backbone appropriately for the environment. Start with AMD. + if (typeof define === 'function' && define.amd) { + define(['underscore', 'jquery', 'exports'], function(_, $, exports) { + // Export global even in AMD case in case this script is loaded with + // others that may still expect a global Backbone. + root.Backbone = factory(root, exports, _, $); + }); + + // Next for Node.js or CommonJS. jQuery may not be needed as a module. + } else if (typeof exports !== 'undefined') { + var _ = require('underscore'), $; + try { $ = require('jquery'); } catch (e) {} + factory(root, exports, _, $); + + // Finally, as a browser global. + } else { + root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +})(function(root, Backbone, _, $) { + + // Initial Setup + // ------------- + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create a local reference to a common array method we'll want to use later. + var slice = Array.prototype.slice; + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.3.3'; + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = $; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... this will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Proxy Backbone class methods to Underscore functions, wrapping the model's + // `attributes` object or collection's `models` array behind the scenes. + // + // collection.filter(function(model) { return model.get('age') > 10 }); + // collection.each(this.addView); + // + // `Function#apply` can be slow so we use the method's arg count, if we know it. + var addMethod = function(length, method, attribute) { + switch (length) { + case 1: return function() { + return _[method](this[attribute]); + }; + case 2: return function(value) { + return _[method](this[attribute], value); + }; + case 3: return function(iteratee, context) { + return _[method](this[attribute], cb(iteratee, this), context); + }; + case 4: return function(iteratee, defaultVal, context) { + return _[method](this[attribute], cb(iteratee, this), defaultVal, context); + }; + default: return function() { + var args = slice.call(arguments); + args.unshift(this[attribute]); + return _[method].apply(_, args); + }; + } + }; + var addUnderscoreMethods = function(Class, methods, attribute) { + _.each(methods, function(length, method) { + if (_[method]) Class.prototype[method] = addMethod(length, method, attribute); + }); + }; + + // Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`. + var cb = function(iteratee, instance) { + if (_.isFunction(iteratee)) return iteratee; + if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee); + if (_.isString(iteratee)) return function(model) { return model.get(iteratee); }; + return iteratee; + }; + var modelMatcher = function(attrs) { + var matcher = _.matches(attrs); + return function(model) { + return matcher(model.attributes); + }; + }; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // a custom event channel. You may bind a callback to an event with `on` or + // remove with `off`; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = {}; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Iterates over the standard `event, callback` (as well as the fancy multiple + // space-separated events `"change blur", callback` and jQuery-style event + // maps `{event: callback}`). + var eventsApi = function(iteratee, events, name, callback, opts) { + var i = 0, names; + if (name && typeof name === 'object') { + // Handle event maps. + if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback; + for (names = _.keys(name); i < names.length ; i++) { + events = eventsApi(iteratee, events, names[i], name[names[i]], opts); + } + } else if (name && eventSplitter.test(name)) { + // Handle space-separated event names by delegating them individually. + for (names = name.split(eventSplitter); i < names.length; i++) { + events = iteratee(events, names[i], callback, opts); + } + } else { + // Finally, standard events. + events = iteratee(events, name, callback, opts); + } + return events; + }; + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + Events.on = function(name, callback, context) { + return internalOn(this, name, callback, context); + }; + + // Guard the `listening` argument from the public API. + var internalOn = function(obj, name, callback, context, listening) { + obj._events = eventsApi(onApi, obj._events || {}, name, callback, { + context: context, + ctx: obj, + listening: listening + }); + + if (listening) { + var listeners = obj._listeners || (obj._listeners = {}); + listeners[listening.id] = listening; + } + + return obj; + }; + + // Inversion-of-control versions of `on`. Tell *this* object to listen to + // an event in another object... keeping track of what it's listening to + // for easier unbinding later. + Events.listenTo = function(obj, name, callback) { + if (!obj) return this; + var id = obj._listenId || (obj._listenId = _.uniqueId('l')); + var listeningTo = this._listeningTo || (this._listeningTo = {}); + var listening = listeningTo[id]; + + // This object is not listening to any other events on `obj` yet. + // Setup the necessary references to track the listening callbacks. + if (!listening) { + var thisId = this._listenId || (this._listenId = _.uniqueId('l')); + listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0}; + } + + // Bind callbacks on obj, and keep track of them on listening. + internalOn(obj, name, callback, this, listening); + return this; + }; + + // The reducing API that adds a callback to the `events` object. + var onApi = function(events, name, callback, options) { + if (callback) { + var handlers = events[name] || (events[name] = []); + var context = options.context, ctx = options.ctx, listening = options.listening; + if (listening) listening.count++; + + handlers.push({callback: callback, context: context, ctx: context || ctx, listening: listening}); + } + return events; + }; + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + Events.off = function(name, callback, context) { + if (!this._events) return this; + this._events = eventsApi(offApi, this._events, name, callback, { + context: context, + listeners: this._listeners + }); + return this; + }; + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + Events.stopListening = function(obj, name, callback) { + var listeningTo = this._listeningTo; + if (!listeningTo) return this; + + var ids = obj ? [obj._listenId] : _.keys(listeningTo); + + for (var i = 0; i < ids.length; i++) { + var listening = listeningTo[ids[i]]; + + // If listening doesn't exist, this object is not currently + // listening to obj. Break out early. + if (!listening) break; + + listening.obj.off(name, callback, this); + } + + return this; + }; + + // The reducing API that removes a callback from the `events` object. + var offApi = function(events, name, callback, options) { + if (!events) return; + + var i = 0, listening; + var context = options.context, listeners = options.listeners; + + // Delete all events listeners and "drop" events. + if (!name && !callback && !context) { + var ids = _.keys(listeners); + for (; i < ids.length; i++) { + listening = listeners[ids[i]]; + delete listeners[listening.id]; + delete listening.listeningTo[listening.objId]; + } + return; + } + + var names = name ? [name] : _.keys(events); + for (; i < names.length; i++) { + name = names[i]; + var handlers = events[name]; + + // Bail out if there are no events stored. + if (!handlers) break; + + // Replace events if there are any remaining. Otherwise, clean up. + var remaining = []; + for (var j = 0; j < handlers.length; j++) { + var handler = handlers[j]; + if ( + callback && callback !== handler.callback && + callback !== handler.callback._callback || + context && context !== handler.context + ) { + remaining.push(handler); + } else { + listening = handler.listening; + if (listening && --listening.count === 0) { + delete listeners[listening.id]; + delete listening.listeningTo[listening.objId]; + } + } + } + + // Update tail event if the list has any events. Otherwise, clean up. + if (remaining.length) { + events[name] = remaining; + } else { + delete events[name]; + } + } + return events; + }; + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, its listener will be removed. If multiple events + // are passed in using the space-separated syntax, the handler will fire + // once for each event, not once for a combination of all events. + Events.once = function(name, callback, context) { + // Map the event into a `{event: once}` object. + var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this)); + if (typeof name === 'string' && context == null) callback = void 0; + return this.on(events, callback, context); + }; + + // Inversion-of-control versions of `once`. + Events.listenToOnce = function(obj, name, callback) { + // Map the event into a `{event: once}` object. + var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj)); + return this.listenTo(obj, events); + }; + + // Reduces the event callbacks into a map of `{event: onceWrapper}`. + // `offer` unbinds the `onceWrapper` after it has been called. + var onceMap = function(map, name, callback, offer) { + if (callback) { + var once = map[name] = _.once(function() { + offer(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + } + return map; + }; + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + Events.trigger = function(name) { + if (!this._events) return this; + + var length = Math.max(0, arguments.length - 1); + var args = Array(length); + for (var i = 0; i < length; i++) args[i] = arguments[i + 1]; + + eventsApi(triggerApi, this._events, name, void 0, args); + return this; + }; + + // Handles triggering the appropriate event callbacks. + var triggerApi = function(objEvents, name, callback, args) { + if (objEvents) { + var events = objEvents[name]; + var allEvents = objEvents.all; + if (events && allEvents) allEvents = allEvents.slice(); + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, [name].concat(args)); + } + return objEvents; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; + } + }; + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId(this.cidPrefix); + this.attributes = {}; + if (options.collection) this.collection = options.collection; + if (options.parse) attrs = this.parse(attrs, options) || {}; + var defaults = _.result(this, 'defaults'); + attrs = _.defaults(_.extend({}, defaults, attrs), defaults); + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // The prefix is used to create the client id which is used to identify models locally. + // You may want to override this if you're experiencing name clashes with model ids. + cidPrefix: 'c', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Special-cased proxy to underscore's `_.matches` method. + matches: function(attrs) { + return !!_.iteratee(attrs, this)(this.attributes); + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + var attrs; + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + var unset = options.unset; + var silent = options.silent; + var changes = []; + var changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + + var current = this.attributes; + var changed = this.changed; + var prev = this._previousAttributes; + + // For each `set` attribute, update or delete the current value. + for (var attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + changed[attr] = val; + } else { + delete changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Update the `id`. + if (this.idAttribute in attrs) this.id = this.get(this.idAttribute); + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = options; + for (var i = 0; i < changes.length; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + options = this._pending; + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var old = this._changing ? this._previousAttributes : this.attributes; + var changed = {}; + for (var attr in diff) { + var val = diff[attr]; + if (_.isEqual(old[attr], val)) continue; + changed[attr] = val; + } + return _.size(changed) ? changed : false; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server, merging the response with the model's + // local attributes. Any changed attributes will trigger a "change" event. + fetch: function(options) { + options = _.extend({parse: true}, options); + var model = this; + var success = options.success; + options.success = function(resp) { + var serverAttrs = options.parse ? model.parse(resp, options) : resp; + if (!model.set(serverAttrs, options)) return false; + if (success) success.call(options.context, model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + // Handle both `"key", value` and `{key: value}` -style arguments. + var attrs; + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options = _.extend({validate: true, parse: true}, options); + var wait = options.wait; + + // If we're not waiting and attributes exist, save acts as + // `set(attr).save(null, opts)` with validation. Otherwise, check if + // the model will be valid when the attributes, if any, are set. + if (attrs && !wait) { + if (!this.set(attrs, options)) return false; + } else if (!this._validate(attrs, options)) { + return false; + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + var model = this; + var success = options.success; + var attributes = this.attributes; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = options.parse ? model.parse(resp, options) : resp; + if (wait) serverAttrs = _.extend({}, attrs, serverAttrs); + if (serverAttrs && !model.set(serverAttrs, options)) return false; + if (success) success.call(options.context, model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + // Set temporary attributes if `{wait: true}` to properly find new ids. + if (attrs && wait) this.attributes = _.extend({}, attributes, attrs); + + var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch' && !options.attrs) options.attrs = attrs; + var xhr = this.sync(method, this, options); + + // Restore attributes. + this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + var wait = options.wait; + + var destroy = function() { + model.stopListening(); + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (wait) destroy(); + if (success) success.call(options.context, model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + var xhr = false; + if (this.isNew()) { + _.defer(options.success); + } else { + wrapError(this, options); + xhr = this.sync('delete', this, options); + } + if (!wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = + _.result(this, 'urlRoot') || + _.result(this.collection, 'url') || + urlError(); + if (this.isNew()) return base; + var id = this.get(this.idAttribute); + return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return !this.has(this.idAttribute); + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.extend({}, options, {validate: true})); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model, mapped to the + // number of arguments they take. + var modelMethods = {keys: 1, values: 1, pairs: 1, invert: 1, pick: 0, + omit: 0, chain: 1, isEmpty: 1}; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + addUnderscoreMethods(Model, modelMethods, 'attributes'); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analogous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, remove: false}; + + // Splices `insert` into `array` at index `at`. + var splice = function(array, insert, at) { + at = Math.min(Math.max(at, 0), array.length); + var tail = Array(array.length - at); + var length = insert.length; + var i; + for (i = 0; i < tail.length; i++) tail[i] = array[i + at]; + for (i = 0; i < length; i++) array[i + at] = insert[i]; + for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i]; + }; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model) { return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. `models` may be Backbone + // Models or raw JavaScript objects to be converted to Models, or any + // combination of the two. + add: function(models, options) { + return this.set(models, _.extend({merge: false}, options, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + options = _.extend({}, options); + var singular = !_.isArray(models); + models = singular ? [models] : models.slice(); + var removed = this._removeModels(models, options); + if (!options.silent && removed.length) { + options.changes = {added: [], merged: [], removed: removed}; + this.trigger('update', this, options); + } + return singular ? removed[0] : removed; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + if (models == null) return; + + options = _.extend({}, setOptions, options); + if (options.parse && !this._isModel(models)) { + models = this.parse(models, options) || []; + } + + var singular = !_.isArray(models); + models = singular ? [models] : models.slice(); + + var at = options.at; + if (at != null) at = +at; + if (at > this.length) at = this.length; + if (at < 0) at += this.length + 1; + + var set = []; + var toAdd = []; + var toMerge = []; + var toRemove = []; + var modelMap = {}; + + var add = options.add; + var merge = options.merge; + var remove = options.remove; + + var sort = false; + var sortable = this.comparator && at == null && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + var model, i; + for (i = 0; i < models.length; i++) { + model = models[i]; + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + var existing = this.get(model); + if (existing) { + if (merge && model !== existing) { + var attrs = this._isModel(model) ? model.attributes : model; + if (options.parse) attrs = existing.parse(attrs, options); + existing.set(attrs, options); + toMerge.push(existing); + if (sortable && !sort) sort = existing.hasChanged(sortAttr); + } + if (!modelMap[existing.cid]) { + modelMap[existing.cid] = true; + set.push(existing); + } + models[i] = existing; + + // If this is a new, valid model, push it to the `toAdd` list. + } else if (add) { + model = models[i] = this._prepareModel(model, options); + if (model) { + toAdd.push(model); + this._addReference(model, options); + modelMap[model.cid] = true; + set.push(model); + } + } + } + + // Remove stale models. + if (remove) { + for (i = 0; i < this.length; i++) { + model = this.models[i]; + if (!modelMap[model.cid]) toRemove.push(model); + } + if (toRemove.length) this._removeModels(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + var orderChanged = false; + var replace = !sortable && add && remove; + if (set.length && replace) { + orderChanged = this.length !== set.length || _.some(this.models, function(m, index) { + return m !== set[index]; + }); + this.models.length = 0; + splice(this.models, set, 0); + this.length = this.models.length; + } else if (toAdd.length) { + if (sortable) sort = true; + splice(this.models, toAdd, at == null ? this.length : at); + this.length = this.models.length; + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + // Unless silenced, it's time to fire all appropriate add/sort/update events. + if (!options.silent) { + for (i = 0; i < toAdd.length; i++) { + if (at != null) options.index = at + i; + model = toAdd[i]; + model.trigger('add', model, this, options); + } + if (sort || orderChanged) this.trigger('sort', this, options); + if (toAdd.length || toRemove.length || toMerge.length) { + options.changes = { + added: toAdd, + removed: toRemove, + merged: toMerge + }; + this.trigger('update', this, options); + } + } + + // Return the added (or merged) model (or models). + return singular ? models[0] : models; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options = options ? _.clone(options) : {}; + for (var i = 0; i < this.models.length; i++) { + this._removeReference(this.models[i], options); + } + options.previousModels = this.models; + this._reset(); + models = this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return models; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + return this.add(model, _.extend({at: this.length}, options)); + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + return this.remove(model, options); + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + return this.add(model, _.extend({at: 0}, options)); + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + return this.remove(model, options); + }, + + // Slice out a sub-array of models from the collection. + slice: function() { + return slice.apply(this.models, arguments); + }, + + // Get a model from the set by id, cid, model object with id or cid + // properties, or an attributes object that is transformed through modelId. + get: function(obj) { + if (obj == null) return void 0; + return this._byId[obj] || + this._byId[this.modelId(obj.attributes || obj)] || + obj.cid && this._byId[obj.cid]; + }, + + // Returns `true` if the model is in the collection. + has: function(obj) { + return this.get(obj) != null; + }, + + // Get the model at the given index. + at: function(index) { + if (index < 0) index += this.length; + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + return this[first ? 'find' : 'filter'](attrs); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + var comparator = this.comparator; + if (!comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + var length = comparator.length; + if (_.isFunction(comparator)) comparator = _.bind(comparator, this); + + // Run sort based on type of `comparator`. + if (length === 1 || _.isString(comparator)) { + this.models = this.sortBy(comparator); + } else { + this.models.sort(comparator); + } + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return this.map(attr + ''); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = _.extend({parse: true}, options); + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success.call(options.context, collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + var wait = options.wait; + model = this._prepareModel(model, options); + if (!model) return false; + if (!wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(m, resp, callbackOpts) { + if (wait) collection.add(m, callbackOpts); + if (success) success.call(callbackOpts.context, m, resp, callbackOpts); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models, { + model: this.model, + comparator: this.comparator + }); + }, + + // Define how to uniquely identify models in the collection. + modelId: function(attrs) { + return attrs[this.model.prototype.idAttribute || 'id']; + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (this._isModel(attrs)) { + if (!attrs.collection) attrs.collection = this; + return attrs; + } + options = options ? _.clone(options) : {}; + options.collection = this; + var model = new this.model(attrs, options); + if (!model.validationError) return model; + this.trigger('invalid', this, model.validationError, options); + return false; + }, + + // Internal method called by both remove and set. + _removeModels: function(models, options) { + var removed = []; + for (var i = 0; i < models.length; i++) { + var model = this.get(models[i]); + if (!model) continue; + + var index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + + // Remove references before triggering 'remove' event to prevent an + // infinite loop. #3693 + delete this._byId[model.cid]; + var id = this.modelId(model.attributes); + if (id != null) delete this._byId[id]; + + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + + removed.push(model); + this._removeReference(model, options); + } + return removed; + }, + + // Method for checking whether an object should be considered a model for + // the purposes of adding to the collection. + _isModel: function(model) { + return model instanceof Model; + }, + + // Internal method to create a model's ties to a collection. + _addReference: function(model, options) { + this._byId[model.cid] = model; + var id = this.modelId(model.attributes); + if (id != null) this._byId[id] = model; + model.on('all', this._onModelEvent, this); + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model, options) { + delete this._byId[model.cid]; + var id = this.modelId(model.attributes); + if (id != null) delete this._byId[id]; + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if (model) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (event === 'change') { + var prevId = this.modelId(model.previousAttributes()); + var id = this.modelId(model.attributes); + if (prevId !== id) { + if (prevId != null) delete this._byId[prevId]; + if (id != null) this._byId[id] = model; + } + } + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var collectionMethods = {forEach: 3, each: 3, map: 3, collect: 3, reduce: 0, + foldl: 0, inject: 0, reduceRight: 0, foldr: 0, find: 3, detect: 3, filter: 3, + select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3, + contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3, + head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3, + without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3, + isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3, + sortBy: 3, indexBy: 3, findIndex: 3, findLastIndex: 3}; + + // Mix in each Underscore method as a proxy to `Collection#models`. + addUnderscoreMethods(Collection, collectionMethods, 'models'); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + _.extend(this, _.pick(options, viewOptions)); + this._ensureElement(); + this.initialize.apply(this, arguments); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be set as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be preferred to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this._removeElement(); + this.stopListening(); + return this; + }, + + // Remove this view's element from the document and all event listeners + // attached to it. Exposed for subclasses using an alternative DOM + // manipulation API. + _removeElement: function() { + this.$el.remove(); + }, + + // Change the view's element (`this.el` property) and re-delegate the + // view's events on the new element. + setElement: function(element) { + this.undelegateEvents(); + this._setElement(element); + this.delegateEvents(); + return this; + }, + + // Creates the `this.el` and `this.$el` references for this view using the + // given `el`. `el` can be a CSS selector or an HTML string, a jQuery + // context or an element. Subclasses can override this to utilize an + // alternative DOM manipulation API and are only required to set the + // `this.el` property. + _setElement: function(el) { + this.$el = el instanceof Backbone.$ ? el : Backbone.$(el); + this.el = this.$el[0]; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save', + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + delegateEvents: function(events) { + events || (events = _.result(this, 'events')); + if (!events) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[method]; + if (!method) continue; + var match = key.match(delegateEventSplitter); + this.delegate(match[1], match[2], _.bind(method, this)); + } + return this; + }, + + // Add a single event listener to the view's element (or a child element + // using `selector`). This only works for delegate-able events: not `focus`, + // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer. + delegate: function(eventName, selector, listener) { + this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener); + return this; + }, + + // Clears all callbacks previously bound to the view by `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + if (this.$el) this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // A finer-grained `undelegateEvents` for removing a single delegated event. + // `selector` and `listener` are both optional. + undelegate: function(eventName, selector, listener) { + this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener); + return this; + }, + + // Produces a DOM element to be assigned to your view. Exposed for + // subclasses using an alternative DOM manipulation API. + _createElement: function(tagName) { + return document.createElement(tagName); + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + this.setElement(this._createElement(_.result(this, 'tagName'))); + this._setAttributes(attrs); + } else { + this.setElement(_.result(this, 'el')); + } + }, + + // Set attributes from a hash on this view's element. Exposed for + // subclasses using an alternative DOM manipulation API. + _setAttributes: function(attributes) { + this.$el.attr(attributes); + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // Pass along `textStatus` and `errorThrown` from jQuery. + var error = options.error; + options.error = function(xhr, textStatus, errorThrown) { + options.textStatus = textStatus; + options.errorThrown = errorThrown; + if (error) error.call(options.context, xhr, textStatus, errorThrown); + }; + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + if (router.execute(callback, args, name) !== false) { + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + } + }); + return this; + }, + + // Execute a route handler with the provided parameters. This is an + // excellent place to do pre-route setup or post-route cleanup. + execute: function(callback, args, name) { + if (callback) callback.apply(this, args); + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional) { + return optional ? match : '([^/?]+)'; + }) + .replace(splatParam, '([^?]*?)'); + return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param, i) { + // Don't decode the search params. + if (i === params.length - 1) return param || null; + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + this.checkUrl = _.bind(this.checkUrl, this); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for stripping urls of hash. + var pathStripper = /#.*$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Are we at the app root? + atRoot: function() { + var path = this.location.pathname.replace(/[^\/]$/, '$&/'); + return path === this.root && !this.getSearch(); + }, + + // Does the pathname match the root? + matchRoot: function() { + var path = this.decodeFragment(this.location.pathname); + var rootPath = path.slice(0, this.root.length - 1) + '/'; + return rootPath === this.root; + }, + + // Unicode characters in `location.pathname` are percent encoded so they're + // decoded for comparison. `%25` should not be decoded since it may be part + // of an encoded parameter. + decodeFragment: function(fragment) { + return decodeURI(fragment.replace(/%25/g, '%2525')); + }, + + // In IE6, the hash fragment and search params are incorrect if the + // fragment contains `?`. + getSearch: function() { + var match = this.location.href.replace(/#.*/, '').match(/\?.+/); + return match ? match[0] : ''; + }, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the pathname and search params, without the root. + getPath: function() { + var path = this.decodeFragment( + this.location.pathname + this.getSearch() + ).slice(this.root.length - 1); + return path.charAt(0) === '/' ? path.slice(1) : path; + }, + + // Get the cross-browser normalized URL fragment from the path or hash. + getFragment: function(fragment) { + if (fragment == null) { + if (this._usePushState || !this._wantsHashChange) { + fragment = this.getPath(); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error('Backbone.history has already been started'); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7); + this._useHashChange = this._wantsHashChange && this._hasHashChange; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.history && this.history.pushState); + this._usePushState = this._wantsPushState && this._hasPushState; + this.fragment = this.getFragment(); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + // Transition from hashChange to pushState or vice versa if both are + // requested. + if (this._wantsHashChange && this._wantsPushState) { + + // If we've started off with a route from a `pushState`-enabled + // browser, but we're currently in a browser that doesn't support it... + if (!this._hasPushState && !this.atRoot()) { + var rootPath = this.root.slice(0, -1) || '/'; + this.location.replace(rootPath + '#' + this.getPath()); + // Return immediately as browser will do redirect to new url + return true; + + // Or if we've started out with a hash-based route, but we're currently + // in a browser where it could be `pushState`-based instead... + } else if (this._hasPushState && this.atRoot()) { + this.navigate(this.getHash(), {replace: true}); + } + + } + + // Proxy an iframe to handle location events if the browser doesn't + // support the `hashchange` event, HTML5 history, or the user wants + // `hashChange` but not `pushState`. + if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) { + this.iframe = document.createElement('iframe'); + this.iframe.src = 'javascript:0'; + this.iframe.style.display = 'none'; + this.iframe.tabIndex = -1; + var body = document.body; + // Using `appendChild` will throw on IE < 9 if the document is not ready. + var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow; + iWindow.document.open(); + iWindow.document.close(); + iWindow.location.hash = '#' + this.fragment; + } + + // Add a cross-platform `addEventListener` shim for older browsers. + var addEventListener = window.addEventListener || function(eventName, listener) { + return attachEvent('on' + eventName, listener); + }; + + // Depending on whether we're using pushState or hashes, and whether + // 'onhashchange' is supported, determine how we check the URL state. + if (this._usePushState) { + addEventListener('popstate', this.checkUrl, false); + } else if (this._useHashChange && !this.iframe) { + addEventListener('hashchange', this.checkUrl, false); + } else if (this._wantsHashChange) { + this._checkUrlInterval = setInterval(this.checkUrl, this.interval); + } + + if (!this.options.silent) return this.loadUrl(); + }, + + // Disable Backbone.history, perhaps temporarily. Not useful in a real app, + // but possibly useful for unit testing Routers. + stop: function() { + // Add a cross-platform `removeEventListener` shim for older browsers. + var removeEventListener = window.removeEventListener || function(eventName, listener) { + return detachEvent('on' + eventName, listener); + }; + + // Remove window listeners. + if (this._usePushState) { + removeEventListener('popstate', this.checkUrl, false); + } else if (this._useHashChange && !this.iframe) { + removeEventListener('hashchange', this.checkUrl, false); + } + + // Clean up the iframe if necessary. + if (this.iframe) { + document.body.removeChild(this.iframe); + this.iframe = null; + } + + // Some environments will throw when clearing an undefined interval. + if (this._checkUrlInterval) clearInterval(this._checkUrlInterval); + History.started = false; + }, + + // Add a route to be tested when the fragment changes. Routes added later + // may override previous routes. + route: function(route, callback) { + this.handlers.unshift({route: route, callback: callback}); + }, + + // Checks the current URL to see if it has changed, and if it has, + // calls `loadUrl`, normalizing across the hidden iframe. + checkUrl: function(e) { + var current = this.getFragment(); + + // If the user pressed the back button, the iframe's hash will have + // changed and we should use that for comparison. + if (current === this.fragment && this.iframe) { + current = this.getHash(this.iframe.contentWindow); + } + + if (current === this.fragment) return false; + if (this.iframe) this.navigate(current); + this.loadUrl(); + }, + + // Attempt to load the current URL fragment. If a route succeeds with a + // match, returns `true`. If no defined routes matches the fragment, + // returns `false`. + loadUrl: function(fragment) { + // If the root doesn't match, no routes can match either. + if (!this.matchRoot()) return false; + fragment = this.fragment = this.getFragment(fragment); + return _.some(this.handlers, function(handler) { + if (handler.route.test(fragment)) { + handler.callback(fragment); + return true; + } + }); + }, + + // Save a fragment into the hash history, or replace the URL state if the + // 'replace' option is passed. You are responsible for properly URL-encoding + // the fragment in advance. + // + // The options object can contain `trigger: true` if you wish to have the + // route callback be fired (not usually desirable), or `replace: true`, if + // you wish to modify the current URL without adding an entry to the history. + navigate: function(fragment, options) { + if (!History.started) return false; + if (!options || options === true) options = {trigger: !!options}; + + // Normalize the fragment. + fragment = this.getFragment(fragment || ''); + + // Don't include a trailing slash on the root. + var rootPath = this.root; + if (fragment === '' || fragment.charAt(0) === '?') { + rootPath = rootPath.slice(0, -1) || '/'; + } + var url = rootPath + fragment; + + // Strip the hash and decode for matching. + fragment = this.decodeFragment(fragment.replace(pathStripper, '')); + + if (this.fragment === fragment) return; + this.fragment = fragment; + + // If pushState is available, we use it to set the fragment as a real URL. + if (this._usePushState) { + this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); + + // If hash changes haven't been explicitly disabled, update the hash + // fragment to store history. + } else if (this._wantsHashChange) { + this._updateHash(this.location, fragment, options.replace); + if (this.iframe && fragment !== this.getHash(this.iframe.contentWindow)) { + var iWindow = this.iframe.contentWindow; + + // Opening and closing the iframe tricks IE7 and earlier to push a + // history entry on hash-tag change. When replace is true, we don't + // want this. + if (!options.replace) { + iWindow.document.open(); + iWindow.document.close(); + } + + this._updateHash(iWindow.location, fragment, options.replace); + } + + // If you've told us that you explicitly don't want fallback hashchange- + // based history, then `navigate` becomes a page refresh. + } else { + return this.location.assign(url); + } + if (options.trigger) return this.loadUrl(fragment); + }, + + // Update the hash location, either replacing the current entry, or adding + // a new one to the browser history. + _updateHash: function(location, fragment, replace) { + if (replace) { + var href = location.href.replace(/(javascript:|#).*$/, ''); + location.replace(href + '#' + fragment); + } else { + // Some browsers require that `hash` contains a leading #. + location.hash = '#' + fragment; + } + } + + }); + + // Create the default Backbone.history. + Backbone.history = new History; + + // Helpers + // ------- + + // Helper function to correctly set up the prototype chain for subclasses. + // Similar to `goog.inherits`, but uses a hash of prototype properties and + // class properties to be extended. + var extend = function(protoProps, staticProps) { + var parent = this; + var child; + + // The constructor function for the new subclass is either defined by you + // (the "constructor" property in your `extend` definition), or defaulted + // by us to simply call the parent constructor. + if (protoProps && _.has(protoProps, 'constructor')) { + child = protoProps.constructor; + } else { + child = function(){ return parent.apply(this, arguments); }; + } + + // Add static properties to the constructor function, if supplied. + _.extend(child, parent, staticProps); + + // Set the prototype chain to inherit from `parent`, without calling + // `parent`'s constructor function and add the prototype properties. + child.prototype = _.create(parent.prototype, protoProps); + child.prototype.constructor = child; + + // Set a convenience property in case the parent's prototype is needed + // later. + child.__super__ = parent.prototype; + + return child; + }; + + // Set up inheritance for the model, collection, router, view and history. + Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend; + + // Throw an error when a URL is needed, and none is supplied. + var urlError = function() { + throw new Error('A "url" property or function must be specified'); + }; + + // Wrap an optional error callback with a fallback error event. + var wrapError = function(model, options) { + var error = options.error; + options.error = function(resp) { + if (error) error.call(options.context, model, resp, options); + model.trigger('error', model, resp, options); + }; + }; + + return Backbone; +}); diff --git a/mdot/mdot_server/mdot_server/app/lib/base64.js b/mdot/mdot_server/mdot_server/app/lib/base64.js new file mode 100644 index 0000000..d5e6af2 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/lib/base64.js @@ -0,0 +1,61 @@ +;(function () { + + var object = typeof exports != 'undefined' ? exports : self; // #8: web workers + var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + + function InvalidCharacterError(message) { + this.message = message; + } + InvalidCharacterError.prototype = new Error; + InvalidCharacterError.prototype.name = 'InvalidCharacterError'; + + // encoder + // [https://gist.github.com/999166] by [https://github.com/nignag] + object.btoa || ( + object.btoa = function (input) { + var str = String(input); + for ( + // initialize result and counter + var block, charCode, idx = 0, map = chars, output = ''; + // if the next str index does not exist: + // change the mapping table to "=" + // check if d has no fractional digits + str.charAt(idx | 0) || (map = '=', idx % 1); + // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 + output += map.charAt(63 & block >> 8 - idx % 1 * 8) + ) { + charCode = str.charCodeAt(idx += 3/4); + if (charCode > 0xFF) { + throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); + } + block = block << 8 | charCode; + } + return output; + }); + + // decoder + // [https://gist.github.com/1020396] by [https://github.com/atk] + object.atob || ( + object.atob = function (input) { + var str = String(input).replace(/=+$/, ''); + if (str.length % 4 == 1) { + throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded."); + } + for ( + // initialize result and counters + var bc = 0, bs, buffer, idx = 0, output = ''; + // get next character + buffer = str.charAt(idx++); + // character found in table? initialize bit storage and add its ascii value; + ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, + // and if not first of each 4 characters, + // convert the first 8 bits to one ascii character + bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 + ) { + // try to find character in table (0-63, not found => -1) + buffer = chars.indexOf(buffer); + } + return output; + }); + +}()); diff --git a/mdot/mdot_server/mdot_server/app/lib/chroma.js b/mdot/mdot_server/mdot_server/app/lib/chroma.js new file mode 100644 index 0000000..54e1410 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/lib/chroma.js @@ -0,0 +1,2465 @@ + +/** + * @license + * + * chroma.js - JavaScript library for color conversions + * + * Copyright (c) 2011-2015, Gregor Aisch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name Gregor Aisch may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +(function() { + var Color, DEG2RAD, LAB_CONSTANTS, PI, PITHIRD, RAD2DEG, TWOPI, _guess_formats, _guess_formats_sorted, _input, _interpolators, abs, atan2, bezier, blend, blend_f, brewer, burn, chroma, clip_rgb, cmyk2rgb, colors, cos, css2rgb, darken, dodge, each, floor, hex2rgb, hsi2rgb, hsl2css, hsl2rgb, hsv2rgb, interpolate, interpolate_hsx, interpolate_lab, interpolate_num, interpolate_rgb, lab2lch, lab2rgb, lab_xyz, lch2lab, lch2rgb, lighten, limit, log, luminance_x, m, max, multiply, normal, num2rgb, overlay, pow, rgb2cmyk, rgb2css, rgb2hex, rgb2hsi, rgb2hsl, rgb2hsv, rgb2lab, rgb2lch, rgb2luminance, rgb2num, rgb2temperature, rgb2xyz, rgb_xyz, rnd, root, round, screen, sin, sqrt, temperature2rgb, type, unpack, w3cx11, xyz_lab, xyz_rgb, + slice = [].slice; + + type = (function() { + + /* + for browser-safe type checking+ + ported from jQuery's $.type + */ + var classToType, len, name, o, ref; + classToType = {}; + ref = "Boolean Number String Function Array Date RegExp Undefined Null".split(" "); + for (o = 0, len = ref.length; o < len; o++) { + name = ref[o]; + classToType["[object " + name + "]"] = name.toLowerCase(); + } + return function(obj) { + var strType; + strType = Object.prototype.toString.call(obj); + return classToType[strType] || "object"; + }; + })(); + + limit = function(x, min, max) { + if (min == null) { + min = 0; + } + if (max == null) { + max = 1; + } + if (x < min) { + x = min; + } + if (x > max) { + x = max; + } + return x; + }; + + unpack = function(args) { + if (args.length >= 3) { + return [].slice.call(args); + } else { + return args[0]; + } + }; + + clip_rgb = function(rgb) { + var i; + for (i in rgb) { + if (i < 3) { + if (rgb[i] < 0) { + rgb[i] = 0; + } + if (rgb[i] > 255) { + rgb[i] = 255; + } + } else if (i === 3) { + if (rgb[i] < 0) { + rgb[i] = 0; + } + if (rgb[i] > 1) { + rgb[i] = 1; + } + } + } + return rgb; + }; + + PI = Math.PI, round = Math.round, cos = Math.cos, floor = Math.floor, pow = Math.pow, log = Math.log, sin = Math.sin, sqrt = Math.sqrt, atan2 = Math.atan2, max = Math.max, abs = Math.abs; + + TWOPI = PI * 2; + + PITHIRD = PI / 3; + + DEG2RAD = PI / 180; + + RAD2DEG = 180 / PI; + + chroma = function() { + if (arguments[0] instanceof Color) { + return arguments[0]; + } + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, arguments, function(){}); + }; + + _interpolators = []; + + if ((typeof module !== "undefined" && module !== null) && (module.exports != null)) { + module.exports = chroma; + } + + if (typeof define === 'function' && define.amd) { + define([], function() { + return chroma; + }); + } else { + root = typeof exports !== "undefined" && exports !== null ? exports : this; + root.chroma = chroma; + } + + chroma.version = '1.1.1'; + + + /** + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + _input = {}; + + _guess_formats = []; + + _guess_formats_sorted = false; + + Color = (function() { + function Color() { + var arg, args, chk, len, len1, me, mode, o, w; + me = this; + args = []; + for (o = 0, len = arguments.length; o < len; o++) { + arg = arguments[o]; + if (arg != null) { + args.push(arg); + } + } + mode = args[args.length - 1]; + if (_input[mode] != null) { + me._rgb = clip_rgb(_input[mode](unpack(args.slice(0, -1)))); + } else { + if (!_guess_formats_sorted) { + _guess_formats = _guess_formats.sort(function(a, b) { + return b.p - a.p; + }); + _guess_formats_sorted = true; + } + for (w = 0, len1 = _guess_formats.length; w < len1; w++) { + chk = _guess_formats[w]; + mode = chk.test.apply(chk, args); + if (mode) { + break; + } + } + if (mode) { + me._rgb = clip_rgb(_input[mode].apply(_input, args)); + } + } + if (me._rgb == null) { + console.warn('unknown format: ' + args); + } + if (me._rgb == null) { + me._rgb = [0, 0, 0]; + } + if (me._rgb.length === 3) { + me._rgb.push(1); + } + } + + Color.prototype.alpha = function(alpha) { + if (arguments.length) { + this._rgb[3] = alpha; + return this; + } + return this._rgb[3]; + }; + + Color.prototype.toString = function() { + return this.name(); + }; + + return Color; + + })(); + + chroma._input = _input; + + + /** + ColorBrewer colors for chroma.js + + Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The + Pennsylvania State University. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed + under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. See the License for the + specific language governing permissions and limitations under the License. + + @preserve + */ + + chroma.brewer = brewer = { + OrRd: ['#fff7ec', '#fee8c8', '#fdd49e', '#fdbb84', '#fc8d59', '#ef6548', '#d7301f', '#b30000', '#7f0000'], + PuBu: ['#fff7fb', '#ece7f2', '#d0d1e6', '#a6bddb', '#74a9cf', '#3690c0', '#0570b0', '#045a8d', '#023858'], + BuPu: ['#f7fcfd', '#e0ecf4', '#bfd3e6', '#9ebcda', '#8c96c6', '#8c6bb1', '#88419d', '#810f7c', '#4d004b'], + Oranges: ['#fff5eb', '#fee6ce', '#fdd0a2', '#fdae6b', '#fd8d3c', '#f16913', '#d94801', '#a63603', '#7f2704'], + BuGn: ['#f7fcfd', '#e5f5f9', '#ccece6', '#99d8c9', '#66c2a4', '#41ae76', '#238b45', '#006d2c', '#00441b'], + YlOrBr: ['#ffffe5', '#fff7bc', '#fee391', '#fec44f', '#fe9929', '#ec7014', '#cc4c02', '#993404', '#662506'], + YlGn: ['#ffffe5', '#f7fcb9', '#d9f0a3', '#addd8e', '#78c679', '#41ab5d', '#238443', '#006837', '#004529'], + Reds: ['#fff5f0', '#fee0d2', '#fcbba1', '#fc9272', '#fb6a4a', '#ef3b2c', '#cb181d', '#a50f15', '#67000d'], + RdPu: ['#fff7f3', '#fde0dd', '#fcc5c0', '#fa9fb5', '#f768a1', '#dd3497', '#ae017e', '#7a0177', '#49006a'], + Greens: ['#f7fcf5', '#e5f5e0', '#c7e9c0', '#a1d99b', '#74c476', '#41ab5d', '#238b45', '#006d2c', '#00441b'], + YlGnBu: ['#ffffd9', '#edf8b1', '#c7e9b4', '#7fcdbb', '#41b6c4', '#1d91c0', '#225ea8', '#253494', '#081d58'], + Purples: ['#fcfbfd', '#efedf5', '#dadaeb', '#bcbddc', '#9e9ac8', '#807dba', '#6a51a3', '#54278f', '#3f007d'], + GnBu: ['#f7fcf0', '#e0f3db', '#ccebc5', '#a8ddb5', '#7bccc4', '#4eb3d3', '#2b8cbe', '#0868ac', '#084081'], + Greys: ['#ffffff', '#f0f0f0', '#d9d9d9', '#bdbdbd', '#969696', '#737373', '#525252', '#252525', '#000000'], + YlOrRd: ['#ffffcc', '#ffeda0', '#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c', '#bd0026', '#800026'], + PuRd: ['#f7f4f9', '#e7e1ef', '#d4b9da', '#c994c7', '#df65b0', '#e7298a', '#ce1256', '#980043', '#67001f'], + Blues: ['#f7fbff', '#deebf7', '#c6dbef', '#9ecae1', '#6baed6', '#4292c6', '#2171b5', '#08519c', '#08306b'], + PuBuGn: ['#fff7fb', '#ece2f0', '#d0d1e6', '#a6bddb', '#67a9cf', '#3690c0', '#02818a', '#016c59', '#014636'], + Spectral: ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2'], + RdYlGn: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#d9ef8b', '#a6d96a', '#66bd63', '#1a9850', '#006837'], + RdBu: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#f7f7f7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061'], + PiYG: ['#8e0152', '#c51b7d', '#de77ae', '#f1b6da', '#fde0ef', '#f7f7f7', '#e6f5d0', '#b8e186', '#7fbc41', '#4d9221', '#276419'], + PRGn: ['#40004b', '#762a83', '#9970ab', '#c2a5cf', '#e7d4e8', '#f7f7f7', '#d9f0d3', '#a6dba0', '#5aae61', '#1b7837', '#00441b'], + RdYlBu: ['#a50026', '#d73027', '#f46d43', '#fdae61', '#fee090', '#ffffbf', '#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695'], + BrBG: ['#543005', '#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e', '#003c30'], + RdGy: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#ffffff', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a'], + PuOr: ['#7f3b08', '#b35806', '#e08214', '#fdb863', '#fee0b6', '#f7f7f7', '#d8daeb', '#b2abd2', '#8073ac', '#542788', '#2d004b'], + Set2: ['#66c2a5', '#fc8d62', '#8da0cb', '#e78ac3', '#a6d854', '#ffd92f', '#e5c494', '#b3b3b3'], + Accent: ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666'], + Set1: ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00', '#ffff33', '#a65628', '#f781bf', '#999999'], + Set3: ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd', '#ccebc5', '#ffed6f'], + Dark2: ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666'], + Paired: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928'], + Pastel2: ['#b3e2cd', '#fdcdac', '#cbd5e8', '#f4cae4', '#e6f5c9', '#fff2ae', '#f1e2cc', '#cccccc'], + Pastel1: ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4', '#fed9a6', '#ffffcc', '#e5d8bd', '#fddaec', '#f2f2f2'] + }; + + + /** + X11 color names + + http://www.w3.org/TR/css3-color/#svg-color + */ + + w3cx11 = { + indigo: "#4b0082", + gold: "#ffd700", + hotpink: "#ff69b4", + firebrick: "#b22222", + indianred: "#cd5c5c", + yellow: "#ffff00", + mistyrose: "#ffe4e1", + darkolivegreen: "#556b2f", + olive: "#808000", + darkseagreen: "#8fbc8f", + pink: "#ffc0cb", + tomato: "#ff6347", + lightcoral: "#f08080", + orangered: "#ff4500", + navajowhite: "#ffdead", + lime: "#00ff00", + palegreen: "#98fb98", + darkslategrey: "#2f4f4f", + greenyellow: "#adff2f", + burlywood: "#deb887", + seashell: "#fff5ee", + mediumspringgreen: "#00fa9a", + fuchsia: "#ff00ff", + papayawhip: "#ffefd5", + blanchedalmond: "#ffebcd", + chartreuse: "#7fff00", + dimgray: "#696969", + black: "#000000", + peachpuff: "#ffdab9", + springgreen: "#00ff7f", + aquamarine: "#7fffd4", + white: "#ffffff", + orange: "#ffa500", + lightsalmon: "#ffa07a", + darkslategray: "#2f4f4f", + brown: "#a52a2a", + ivory: "#fffff0", + dodgerblue: "#1e90ff", + peru: "#cd853f", + lawngreen: "#7cfc00", + chocolate: "#d2691e", + crimson: "#dc143c", + forestgreen: "#228b22", + darkgrey: "#a9a9a9", + lightseagreen: "#20b2aa", + cyan: "#00ffff", + mintcream: "#f5fffa", + silver: "#c0c0c0", + antiquewhite: "#faebd7", + mediumorchid: "#ba55d3", + skyblue: "#87ceeb", + gray: "#808080", + darkturquoise: "#00ced1", + goldenrod: "#daa520", + darkgreen: "#006400", + floralwhite: "#fffaf0", + darkviolet: "#9400d3", + darkgray: "#a9a9a9", + moccasin: "#ffe4b5", + saddlebrown: "#8b4513", + grey: "#808080", + darkslateblue: "#483d8b", + lightskyblue: "#87cefa", + lightpink: "#ffb6c1", + mediumvioletred: "#c71585", + slategrey: "#708090", + red: "#ff0000", + deeppink: "#ff1493", + limegreen: "#32cd32", + darkmagenta: "#8b008b", + palegoldenrod: "#eee8aa", + plum: "#dda0dd", + turquoise: "#40e0d0", + lightgrey: "#d3d3d3", + lightgoldenrodyellow: "#fafad2", + darkgoldenrod: "#b8860b", + lavender: "#e6e6fa", + maroon: "#800000", + yellowgreen: "#9acd32", + sandybrown: "#f4a460", + thistle: "#d8bfd8", + violet: "#ee82ee", + navy: "#000080", + magenta: "#ff00ff", + dimgrey: "#696969", + tan: "#d2b48c", + rosybrown: "#bc8f8f", + olivedrab: "#6b8e23", + blue: "#0000ff", + lightblue: "#add8e6", + ghostwhite: "#f8f8ff", + honeydew: "#f0fff0", + cornflowerblue: "#6495ed", + slateblue: "#6a5acd", + linen: "#faf0e6", + darkblue: "#00008b", + powderblue: "#b0e0e6", + seagreen: "#2e8b57", + darkkhaki: "#bdb76b", + snow: "#fffafa", + sienna: "#a0522d", + mediumblue: "#0000cd", + royalblue: "#4169e1", + lightcyan: "#e0ffff", + green: "#008000", + mediumpurple: "#9370db", + midnightblue: "#191970", + cornsilk: "#fff8dc", + paleturquoise: "#afeeee", + bisque: "#ffe4c4", + slategray: "#708090", + darkcyan: "#008b8b", + khaki: "#f0e68c", + wheat: "#f5deb3", + teal: "#008080", + darkorchid: "#9932cc", + deepskyblue: "#00bfff", + salmon: "#fa8072", + darkred: "#8b0000", + steelblue: "#4682b4", + palevioletred: "#db7093", + lightslategray: "#778899", + aliceblue: "#f0f8ff", + lightslategrey: "#778899", + lightgreen: "#90ee90", + orchid: "#da70d6", + gainsboro: "#dcdcdc", + mediumseagreen: "#3cb371", + lightgray: "#d3d3d3", + mediumturquoise: "#48d1cc", + lemonchiffon: "#fffacd", + cadetblue: "#5f9ea0", + lightyellow: "#ffffe0", + lavenderblush: "#fff0f5", + coral: "#ff7f50", + purple: "#800080", + aqua: "#00ffff", + whitesmoke: "#f5f5f5", + mediumslateblue: "#7b68ee", + darkorange: "#ff8c00", + mediumaquamarine: "#66cdaa", + darksalmon: "#e9967a", + beige: "#f5f5dc", + blueviolet: "#8a2be2", + azure: "#f0ffff", + lightsteelblue: "#b0c4de", + oldlace: "#fdf5e6", + rebeccapurple: "#663399" + }; + + chroma.colors = colors = w3cx11; + + lab2rgb = function() { + var a, args, b, g, l, r, x, y, z; + args = unpack(arguments); + l = args[0], a = args[1], b = args[2]; + y = (l + 16) / 116; + x = isNaN(a) ? y : y + a / 500; + z = isNaN(b) ? y : y - b / 200; + y = LAB_CONSTANTS.Yn * lab_xyz(y); + x = LAB_CONSTANTS.Xn * lab_xyz(x); + z = LAB_CONSTANTS.Zn * lab_xyz(z); + r = xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z); + g = xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z); + b = xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z); + r = limit(r, 0, 255); + g = limit(g, 0, 255); + b = limit(b, 0, 255); + return [r, g, b, args.length > 3 ? args[3] : 1]; + }; + + xyz_rgb = function(r) { + return round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * pow(r, 1 / 2.4) - 0.055)); + }; + + lab_xyz = function(t) { + if (t > LAB_CONSTANTS.t1) { + return t * t * t; + } else { + return LAB_CONSTANTS.t2 * (t - LAB_CONSTANTS.t0); + } + }; + + LAB_CONSTANTS = { + Kn: 18, + Xn: 0.950470, + Yn: 1, + Zn: 1.088830, + t0: 0.137931034, + t1: 0.206896552, + t2: 0.12841855, + t3: 0.008856452 + }; + + rgb2lab = function() { + var b, g, r, ref, ref1, x, y, z; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + ref1 = rgb2xyz(r, g, b), x = ref1[0], y = ref1[1], z = ref1[2]; + return [116 * y - 16, 500 * (x - y), 200 * (y - z)]; + }; + + rgb_xyz = function(r) { + if ((r /= 255) <= 0.04045) { + return r / 12.92; + } else { + return pow((r + 0.055) / 1.055, 2.4); + } + }; + + xyz_lab = function(t) { + if (t > LAB_CONSTANTS.t3) { + return pow(t, 1 / 3); + } else { + return t / LAB_CONSTANTS.t2 + LAB_CONSTANTS.t0; + } + }; + + rgb2xyz = function() { + var b, g, r, ref, x, y, z; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = rgb_xyz(r); + g = rgb_xyz(g); + b = rgb_xyz(b); + x = xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / LAB_CONSTANTS.Xn); + y = xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / LAB_CONSTANTS.Yn); + z = xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / LAB_CONSTANTS.Zn); + return [x, y, z]; + }; + + chroma.lab = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['lab']), function(){}); + }; + + _input.lab = lab2rgb; + + Color.prototype.lab = function() { + return rgb2lab(this._rgb); + }; + + bezier = function(colors) { + var I, I0, I1, c, lab0, lab1, lab2, lab3, ref, ref1, ref2; + colors = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(chroma(c)); + } + return results; + })(); + if (colors.length === 2) { + ref = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref[0], lab1 = ref[1]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push(lab0[i] + t * (lab1[i] - lab0[i])); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 3) { + ref1 = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref1[0], lab1 = ref1[1], lab2 = ref1[2]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push((1 - t) * (1 - t) * lab0[i] + 2 * (1 - t) * t * lab1[i] + t * t * lab2[i]); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 4) { + ref2 = (function() { + var len, o, results; + results = []; + for (o = 0, len = colors.length; o < len; o++) { + c = colors[o]; + results.push(c.lab()); + } + return results; + })(), lab0 = ref2[0], lab1 = ref2[1], lab2 = ref2[2], lab3 = ref2[3]; + I = function(t) { + var i, lab; + lab = (function() { + var o, results; + results = []; + for (i = o = 0; o <= 2; i = ++o) { + results.push((1 - t) * (1 - t) * (1 - t) * lab0[i] + 3 * (1 - t) * (1 - t) * t * lab1[i] + 3 * (1 - t) * t * t * lab2[i] + t * t * t * lab3[i]); + } + return results; + })(); + return chroma.lab.apply(chroma, lab); + }; + } else if (colors.length === 5) { + I0 = bezier(colors.slice(0, 3)); + I1 = bezier(colors.slice(2, 5)); + I = function(t) { + if (t < 0.5) { + return I0(t * 2); + } else { + return I1((t - 0.5) * 2); + } + }; + } + return I; + }; + + chroma.bezier = function(colors) { + var f; + f = bezier(colors); + f.scale = function() { + return chroma.scale(f); + }; + return f; + }; + + + /* + chroma.js + + Copyright (c) 2011-2013, Gregor Aisch + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name Gregor Aisch may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL GREGOR AISCH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + @source: https://github.com/gka/chroma.js + */ + + chroma.cubehelix = function(start, rotations, hue, gamma, lightness) { + var dh, dl, f; + if (start == null) { + start = 300; + } + if (rotations == null) { + rotations = -1.5; + } + if (hue == null) { + hue = 1; + } + if (gamma == null) { + gamma = 1; + } + if (lightness == null) { + lightness = [0, 1]; + } + dl = lightness[1] - lightness[0]; + dh = 0; + f = function(fract) { + var a, amp, b, cos_a, g, h, l, r, sin_a; + a = TWOPI * ((start + 120) / 360 + rotations * fract); + l = pow(lightness[0] + dl * fract, gamma); + h = dh !== 0 ? hue[0] + fract * dh : hue; + amp = h * l * (1 - l) / 2; + cos_a = cos(a); + sin_a = sin(a); + r = l + amp * (-0.14861 * cos_a + 1.78277 * sin_a); + g = l + amp * (-0.29227 * cos_a - 0.90649 * sin_a); + b = l + amp * (+1.97294 * cos_a); + return chroma(clip_rgb([r * 255, g * 255, b * 255])); + }; + f.start = function(s) { + if (s == null) { + return start; + } + start = s; + return f; + }; + f.rotations = function(r) { + if (r == null) { + return rotations; + } + rotations = r; + return f; + }; + f.gamma = function(g) { + if (g == null) { + return gamma; + } + gamma = g; + return f; + }; + f.hue = function(h) { + if (h == null) { + return hue; + } + hue = h; + if (type(hue) === 'array') { + dh = hue[1] - hue[0]; + if (dh === 0) { + hue = hue[1]; + } + } else { + dh = 0; + } + return f; + }; + f.lightness = function(h) { + if (h == null) { + return lightness; + } + lightness = h; + if (type(lightness) === 'array') { + dl = lightness[1] - lightness[0]; + if (dl === 0) { + lightness = lightness[1]; + } + } else { + dl = 0; + } + return f; + }; + f.scale = function() { + return chroma.scale(f); + }; + f.hue(hue); + return f; + }; + + chroma.random = function() { + var code, digits, i, o; + digits = '0123456789abcdef'; + code = '#'; + for (i = o = 0; o < 6; i = ++o) { + code += digits.charAt(floor(Math.random() * 16)); + } + return new Color(code); + }; + + _input.rgb = function() { + var k, ref, results, v; + ref = unpack(arguments); + results = []; + for (k in ref) { + v = ref[k]; + results.push(v); + } + return results; + }; + + chroma.rgb = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['rgb']), function(){}); + }; + + Color.prototype.rgb = function() { + return this._rgb.slice(0, 3); + }; + + Color.prototype.rgba = function() { + return this._rgb; + }; + + _guess_formats.push({ + p: 15, + test: function(n) { + var a; + a = unpack(arguments); + if (type(a) === 'array' && a.length === 3) { + return 'rgb'; + } + if (a.length === 4 && type(a[3]) === "number" && a[3] >= 0 && a[3] <= 1) { + return 'rgb'; + } + } + }); + + hex2rgb = function(hex) { + var a, b, g, r, rgb, u; + if (hex.match(/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/)) { + if (hex.length === 4 || hex.length === 7) { + hex = hex.substr(1); + } + if (hex.length === 3) { + hex = hex.split(""); + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + u = parseInt(hex, 16); + r = u >> 16; + g = u >> 8 & 0xFF; + b = u & 0xFF; + return [r, g, b, 1]; + } + if (hex.match(/^#?([A-Fa-f0-9]{8})$/)) { + if (hex.length === 9) { + hex = hex.substr(1); + } + u = parseInt(hex, 16); + r = u >> 24 & 0xFF; + g = u >> 16 & 0xFF; + b = u >> 8 & 0xFF; + a = round((u & 0xFF) / 0xFF * 100) / 100; + return [r, g, b, a]; + } + if ((_input.css != null) && (rgb = _input.css(hex))) { + return rgb; + } + throw "unknown color: " + hex; + }; + + rgb2hex = function(channels, mode) { + var a, b, g, hxa, r, str, u; + if (mode == null) { + mode = 'rgb'; + } + r = channels[0], g = channels[1], b = channels[2], a = channels[3]; + u = r << 16 | g << 8 | b; + str = "000000" + u.toString(16); + str = str.substr(str.length - 6); + hxa = '0' + round(a * 255).toString(16); + hxa = hxa.substr(hxa.length - 2); + return "#" + (function() { + switch (mode.toLowerCase()) { + case 'rgba': + return str + hxa; + case 'argb': + return hxa + str; + default: + return str; + } + })(); + }; + + _input.hex = function(h) { + return hex2rgb(h); + }; + + chroma.hex = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['hex']), function(){}); + }; + + Color.prototype.hex = function(mode) { + if (mode == null) { + mode = 'rgb'; + } + return rgb2hex(this._rgb, mode); + }; + + _guess_formats.push({ + p: 10, + test: function(n) { + if (arguments.length === 1 && type(n) === "string") { + return 'hex'; + } + } + }); + + hsl2rgb = function() { + var args, b, c, g, h, i, l, o, r, ref, s, t1, t2, t3; + args = unpack(arguments); + h = args[0], s = args[1], l = args[2]; + if (s === 0) { + r = g = b = l * 255; + } else { + t3 = [0, 0, 0]; + c = [0, 0, 0]; + t2 = l < 0.5 ? l * (1 + s) : l + s - l * s; + t1 = 2 * l - t2; + h /= 360; + t3[0] = h + 1 / 3; + t3[1] = h; + t3[2] = h - 1 / 3; + for (i = o = 0; o <= 2; i = ++o) { + if (t3[i] < 0) { + t3[i] += 1; + } + if (t3[i] > 1) { + t3[i] -= 1; + } + if (6 * t3[i] < 1) { + c[i] = t1 + (t2 - t1) * 6 * t3[i]; + } else if (2 * t3[i] < 1) { + c[i] = t2; + } else if (3 * t3[i] < 2) { + c[i] = t1 + (t2 - t1) * ((2 / 3) - t3[i]) * 6; + } else { + c[i] = t1; + } + } + ref = [round(c[0] * 255), round(c[1] * 255), round(c[2] * 255)], r = ref[0], g = ref[1], b = ref[2]; + } + if (args.length > 3) { + return [r, g, b, args[3]]; + } else { + return [r, g, b]; + } + }; + + rgb2hsl = function(r, g, b) { + var h, l, min, ref, s; + if (r !== void 0 && r.length >= 3) { + ref = r, r = ref[0], g = ref[1], b = ref[2]; + } + r /= 255; + g /= 255; + b /= 255; + min = Math.min(r, g, b); + max = Math.max(r, g, b); + l = (max + min) / 2; + if (max === min) { + s = 0; + h = Number.NaN; + } else { + s = l < 0.5 ? (max - min) / (max + min) : (max - min) / (2 - max - min); + } + if (r === max) { + h = (g - b) / (max - min); + } else if (g === max) { + h = 2 + (b - r) / (max - min); + } else if (b === max) { + h = 4 + (r - g) / (max - min); + } + h *= 60; + if (h < 0) { + h += 360; + } + return [h, s, l]; + }; + + chroma.hsl = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['hsl']), function(){}); + }; + + _input.hsl = hsl2rgb; + + Color.prototype.hsl = function() { + return rgb2hsl(this._rgb); + }; + + hsv2rgb = function() { + var args, b, f, g, h, i, p, q, r, ref, ref1, ref2, ref3, ref4, ref5, s, t, v; + args = unpack(arguments); + h = args[0], s = args[1], v = args[2]; + v *= 255; + if (s === 0) { + r = g = b = v; + } else { + if (h === 360) { + h = 0; + } + if (h > 360) { + h -= 360; + } + if (h < 0) { + h += 360; + } + h /= 60; + i = floor(h); + f = h - i; + p = v * (1 - s); + q = v * (1 - s * f); + t = v * (1 - s * (1 - f)); + switch (i) { + case 0: + ref = [v, t, p], r = ref[0], g = ref[1], b = ref[2]; + break; + case 1: + ref1 = [q, v, p], r = ref1[0], g = ref1[1], b = ref1[2]; + break; + case 2: + ref2 = [p, v, t], r = ref2[0], g = ref2[1], b = ref2[2]; + break; + case 3: + ref3 = [p, q, v], r = ref3[0], g = ref3[1], b = ref3[2]; + break; + case 4: + ref4 = [t, p, v], r = ref4[0], g = ref4[1], b = ref4[2]; + break; + case 5: + ref5 = [v, p, q], r = ref5[0], g = ref5[1], b = ref5[2]; + } + } + r = round(r); + g = round(g); + b = round(b); + return [r, g, b, args.length > 3 ? args[3] : 1]; + }; + + rgb2hsv = function() { + var b, delta, g, h, min, r, ref, s, v; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + min = Math.min(r, g, b); + max = Math.max(r, g, b); + delta = max - min; + v = max / 255.0; + if (max === 0) { + h = Number.NaN; + s = 0; + } else { + s = delta / max; + if (r === max) { + h = (g - b) / delta; + } + if (g === max) { + h = 2 + (b - r) / delta; + } + if (b === max) { + h = 4 + (r - g) / delta; + } + h *= 60; + if (h < 0) { + h += 360; + } + } + return [h, s, v]; + }; + + chroma.hsv = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['hsv']), function(){}); + }; + + _input.hsv = hsv2rgb; + + Color.prototype.hsv = function() { + return rgb2hsv(this._rgb); + }; + + num2rgb = function(num) { + var b, g, r; + if (type(num) === "number" && num >= 0 && num <= 0xFFFFFF) { + r = num >> 16; + g = (num >> 8) & 0xFF; + b = num & 0xFF; + return [r, g, b, 1]; + } + console.warn("unknown num color: " + num); + return [0, 0, 0, 1]; + }; + + rgb2num = function() { + var b, g, r, ref; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + return (r << 16) + (g << 8) + b; + }; + + chroma.num = function(num) { + return new Color(num, 'num'); + }; + + Color.prototype.num = function(mode) { + if (mode == null) { + mode = 'rgb'; + } + return rgb2num(this._rgb, mode); + }; + + _input.num = num2rgb; + + _guess_formats.push({ + p: 10, + test: function(n) { + if (arguments.length === 1 && type(n) === "number" && n >= 0 && n <= 0xFFFFFF) { + return 'num'; + } + } + }); + + css2rgb = function(css) { + var aa, ab, hsl, i, m, o, rgb, w; + css = css.toLowerCase(); + if ((chroma.colors != null) && chroma.colors[css]) { + return hex2rgb(chroma.colors[css]); + } + if (m = css.match(/rgb\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*\)/)) { + rgb = m.slice(1, 4); + for (i = o = 0; o <= 2; i = ++o) { + rgb[i] = +rgb[i]; + } + rgb[3] = 1; + } else if (m = css.match(/rgba\(\s*(\-?\d+),\s*(\-?\d+)\s*,\s*(\-?\d+)\s*,\s*([01]|[01]?\.\d+)\)/)) { + rgb = m.slice(1, 5); + for (i = w = 0; w <= 3; i = ++w) { + rgb[i] = +rgb[i]; + } + } else if (m = css.match(/rgb\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/)) { + rgb = m.slice(1, 4); + for (i = aa = 0; aa <= 2; i = ++aa) { + rgb[i] = round(rgb[i] * 2.55); + } + rgb[3] = 1; + } else if (m = css.match(/rgba\(\s*(\-?\d+(?:\.\d+)?)%,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/)) { + rgb = m.slice(1, 5); + for (i = ab = 0; ab <= 2; i = ++ab) { + rgb[i] = round(rgb[i] * 2.55); + } + rgb[3] = +rgb[3]; + } else if (m = css.match(/hsl\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*\)/)) { + hsl = m.slice(1, 4); + hsl[1] *= 0.01; + hsl[2] *= 0.01; + rgb = hsl2rgb(hsl); + rgb[3] = 1; + } else if (m = css.match(/hsla\(\s*(\-?\d+(?:\.\d+)?),\s*(\-?\d+(?:\.\d+)?)%\s*,\s*(\-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)/)) { + hsl = m.slice(1, 4); + hsl[1] *= 0.01; + hsl[2] *= 0.01; + rgb = hsl2rgb(hsl); + rgb[3] = +m[4]; + } + return rgb; + }; + + rgb2css = function(rgba) { + var mode; + mode = rgba[3] < 1 ? 'rgba' : 'rgb'; + if (mode === 'rgb') { + return mode + '(' + rgba.slice(0, 3).map(round).join(',') + ')'; + } else if (mode === 'rgba') { + return mode + '(' + rgba.slice(0, 3).map(round).join(',') + ',' + rgba[3] + ')'; + } else { + + } + }; + + rnd = function(a) { + return round(a * 100) / 100; + }; + + hsl2css = function(hsl, alpha) { + var mode; + mode = alpha < 1 ? 'hsla' : 'hsl'; + hsl[0] = rnd(hsl[0] || 0); + hsl[1] = rnd(hsl[1] * 100) + '%'; + hsl[2] = rnd(hsl[2] * 100) + '%'; + if (mode === 'hsla') { + hsl[3] = alpha; + } + return mode + '(' + hsl.join(',') + ')'; + }; + + _input.css = function(h) { + return css2rgb(h); + }; + + chroma.css = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['css']), function(){}); + }; + + Color.prototype.css = function(mode) { + if (mode == null) { + mode = 'rgb'; + } + if (mode.slice(0, 3) === 'rgb') { + return rgb2css(this._rgb); + } else if (mode.slice(0, 3) === 'hsl') { + return hsl2css(this.hsl(), this.alpha()); + } + }; + + _input.named = function(name) { + return hex2rgb(w3cx11[name]); + }; + + _guess_formats.push({ + p: 20, + test: function(n) { + if (arguments.length === 1 && (w3cx11[n] != null)) { + return 'named'; + } + } + }); + + Color.prototype.name = function(n) { + var h, k; + if (arguments.length) { + if (w3cx11[n]) { + this._rgb = hex2rgb(w3cx11[n]); + } + this._rgb[3] = 1; + this; + } + h = this.hex(); + for (k in w3cx11) { + if (h === w3cx11[k]) { + return k; + } + } + return h; + }; + + lch2lab = function() { + + /* + Convert from a qualitative parameter h and a quantitative parameter l to a 24-bit pixel. + These formulas were invented by David Dalrymple to obtain maximum contrast without going + out of gamut if the parameters are in the range 0-1. + + A saturation multiplier was added by Gregor Aisch + */ + var c, h, l, ref; + ref = unpack(arguments), l = ref[0], c = ref[1], h = ref[2]; + h = h * DEG2RAD; + return [l, cos(h) * c, sin(h) * c]; + }; + + lch2rgb = function() { + var L, a, args, b, c, g, h, l, r, ref, ref1; + args = unpack(arguments); + l = args[0], c = args[1], h = args[2]; + ref = lch2lab(l, c, h), L = ref[0], a = ref[1], b = ref[2]; + ref1 = lab2rgb(L, a, b), r = ref1[0], g = ref1[1], b = ref1[2]; + return [limit(r, 0, 255), limit(g, 0, 255), limit(b, 0, 255), args.length > 3 ? args[3] : 1]; + }; + + lab2lch = function() { + var a, b, c, h, l, ref; + ref = unpack(arguments), l = ref[0], a = ref[1], b = ref[2]; + c = sqrt(a * a + b * b); + h = (atan2(b, a) * RAD2DEG + 360) % 360; + if (round(c * 10000) === 0) { + h = Number.NaN; + } + return [l, c, h]; + }; + + rgb2lch = function() { + var a, b, g, l, r, ref, ref1; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + ref1 = rgb2lab(r, g, b), l = ref1[0], a = ref1[1], b = ref1[2]; + return lab2lch(l, a, b); + }; + + chroma.lch = function() { + var args; + args = unpack(arguments); + return new Color(args, 'lch'); + }; + + chroma.hcl = function() { + var args; + args = unpack(arguments); + return new Color(args, 'hcl'); + }; + + _input.lch = lch2rgb; + + _input.hcl = function() { + var c, h, l, ref; + ref = unpack(arguments), h = ref[0], c = ref[1], l = ref[2]; + return lch2rgb([l, c, h]); + }; + + Color.prototype.lch = function() { + return rgb2lch(this._rgb); + }; + + Color.prototype.hcl = function() { + return rgb2lch(this._rgb).reverse(); + }; + + rgb2cmyk = function(mode) { + var b, c, f, g, k, m, r, ref, y; + if (mode == null) { + mode = 'rgb'; + } + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = r / 255; + g = g / 255; + b = b / 255; + k = 1 - Math.max(r, Math.max(g, b)); + f = k < 1 ? 1 / (1 - k) : 0; + c = (1 - r - k) * f; + m = (1 - g - k) * f; + y = (1 - b - k) * f; + return [c, m, y, k]; + }; + + cmyk2rgb = function() { + var alpha, args, b, c, g, k, m, r, y; + args = unpack(arguments); + c = args[0], m = args[1], y = args[2], k = args[3]; + alpha = args.length > 4 ? args[4] : 1; + if (k === 1) { + return [0, 0, 0, alpha]; + } + r = c >= 1 ? 0 : round(255 * (1 - c) * (1 - k)); + g = m >= 1 ? 0 : round(255 * (1 - m) * (1 - k)); + b = y >= 1 ? 0 : round(255 * (1 - y) * (1 - k)); + return [r, g, b, alpha]; + }; + + _input.cmyk = function() { + return cmyk2rgb(unpack(arguments)); + }; + + chroma.cmyk = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['cmyk']), function(){}); + }; + + Color.prototype.cmyk = function() { + return rgb2cmyk(this._rgb); + }; + + _input.gl = function() { + var i, k, o, rgb, v; + rgb = (function() { + var ref, results; + ref = unpack(arguments); + results = []; + for (k in ref) { + v = ref[k]; + results.push(v); + } + return results; + }).apply(this, arguments); + for (i = o = 0; o <= 2; i = ++o) { + rgb[i] *= 255; + } + return rgb; + }; + + chroma.gl = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['gl']), function(){}); + }; + + Color.prototype.gl = function() { + var rgb; + rgb = this._rgb; + return [rgb[0] / 255, rgb[1] / 255, rgb[2] / 255, rgb[3]]; + }; + + rgb2luminance = function(r, g, b) { + var ref; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + r = luminance_x(r); + g = luminance_x(g); + b = luminance_x(b); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + }; + + luminance_x = function(x) { + x /= 255; + if (x <= 0.03928) { + return x / 12.92; + } else { + return pow((x + 0.055) / 1.055, 2.4); + } + }; + + _interpolators = []; + + interpolate = function(col1, col2, f, m) { + var interpol, len, o, res; + if (f == null) { + f = 0.5; + } + if (m == null) { + m = 'rgb'; + } + + /* + interpolates between colors + f = 0 --> me + f = 1 --> col + */ + if (type(col1) !== 'object') { + col1 = chroma(col1); + } + if (type(col2) !== 'object') { + col2 = chroma(col2); + } + for (o = 0, len = _interpolators.length; o < len; o++) { + interpol = _interpolators[o]; + if (m === interpol[0]) { + res = interpol[1](col1, col2, f, m); + break; + } + } + if (res == null) { + throw "color mode " + m + " is not supported"; + } + res.alpha(col1.alpha() + f * (col2.alpha() - col1.alpha())); + return res; + }; + + chroma.interpolate = interpolate; + + Color.prototype.interpolate = function(col2, f, m) { + return interpolate(this, col2, f, m); + }; + + chroma.mix = interpolate; + + Color.prototype.mix = Color.prototype.interpolate; + + interpolate_rgb = function(col1, col2, f, m) { + var xyz0, xyz1; + xyz0 = col1._rgb; + xyz1 = col2._rgb; + return new Color(xyz0[0] + f * (xyz1[0] - xyz0[0]), xyz0[1] + f * (xyz1[1] - xyz0[1]), xyz0[2] + f * (xyz1[2] - xyz0[2]), m); + }; + + _interpolators.push(['rgb', interpolate_rgb]); + + Color.prototype.luminance = function(lum, mode) { + var cur_lum, eps, max_iter, test; + if (mode == null) { + mode = 'rgb'; + } + if (!arguments.length) { + return rgb2luminance(this._rgb); + } + if (lum === 0) { + this._rgb = [0, 0, 0, this._rgb[3]]; + } else if (lum === 1) { + this._rgb = [255, 255, 255, this._rgb[3]]; + } else { + eps = 1e-7; + max_iter = 20; + test = function(l, h) { + var lm, m; + m = l.interpolate(h, 0.5, mode); + lm = m.luminance(); + if (Math.abs(lum - lm) < eps || !max_iter--) { + return m; + } + if (lm > lum) { + return test(l, m); + } + return test(m, h); + }; + cur_lum = rgb2luminance(this._rgb); + this._rgb = (cur_lum > lum ? test(chroma('black'), this) : test(this, chroma('white'))).rgba(); + } + return this; + }; + + temperature2rgb = function(kelvin) { + var b, g, r, temp; + temp = kelvin / 100; + if (temp < 66) { + r = 255; + g = -155.25485562709179 - 0.44596950469579133 * (g = temp - 2) + 104.49216199393888 * log(g); + b = temp < 20 ? 0 : -254.76935184120902 + 0.8274096064007395 * (b = temp - 10) + 115.67994401066147 * log(b); + } else { + r = 351.97690566805693 + 0.114206453784165 * (r = temp - 55) - 40.25366309332127 * log(r); + g = 325.4494125711974 + 0.07943456536662342 * (g = temp - 50) - 28.0852963507957 * log(g); + b = 255; + } + return clip_rgb([r, g, b]); + }; + + rgb2temperature = function() { + var b, eps, g, maxTemp, minTemp, r, ref, rgb, temp; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + minTemp = 1000; + maxTemp = 40000; + eps = 0.4; + while (maxTemp - minTemp > eps) { + temp = (maxTemp + minTemp) * 0.5; + rgb = temperature2rgb(temp); + if ((rgb[2] / rgb[0]) >= (b / r)) { + maxTemp = temp; + } else { + minTemp = temp; + } + } + return round(temp); + }; + + chroma.temperature = chroma.kelvin = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['temperature']), function(){}); + }; + + _input.temperature = _input.kelvin = _input.K = temperature2rgb; + + Color.prototype.temperature = function() { + return rgb2temperature(this._rgb); + }; + + Color.prototype.kelvin = Color.prototype.temperature; + + chroma.contrast = function(a, b) { + var l1, l2, ref, ref1; + if ((ref = type(a)) === 'string' || ref === 'number') { + a = new Color(a); + } + if ((ref1 = type(b)) === 'string' || ref1 === 'number') { + b = new Color(b); + } + l1 = a.luminance(); + l2 = b.luminance(); + if (l1 > l2) { + return (l1 + 0.05) / (l2 + 0.05); + } else { + return (l2 + 0.05) / (l1 + 0.05); + } + }; + + Color.prototype.get = function(modechan) { + var channel, i, me, mode, ref, src; + me = this; + ref = modechan.split('.'), mode = ref[0], channel = ref[1]; + src = me[mode](); + if (channel) { + i = mode.indexOf(channel); + if (i > -1) { + return src[i]; + } else { + return console.warn('unknown channel ' + channel + ' in mode ' + mode); + } + } else { + return src; + } + }; + + Color.prototype.set = function(modechan, value) { + var channel, i, me, mode, ref, src; + me = this; + ref = modechan.split('.'), mode = ref[0], channel = ref[1]; + if (channel) { + src = me[mode](); + i = mode.indexOf(channel); + if (i > -1) { + if (type(value) === 'string') { + switch (value.charAt(0)) { + case '+': + src[i] += +value; + break; + case '-': + src[i] += +value; + break; + case '*': + src[i] *= +(value.substr(1)); + break; + case '/': + src[i] /= +(value.substr(1)); + break; + default: + src[i] = +value; + } + } else { + src[i] = value; + } + } else { + console.warn('unknown channel ' + channel + ' in mode ' + mode); + } + } else { + src = value; + } + me._rgb = chroma(src, mode).alpha(me.alpha())._rgb; + return me; + }; + + Color.prototype.darken = function(amount) { + var lab, me; + if (amount == null) { + amount = 1; + } + me = this; + lab = me.lab(); + lab[0] -= LAB_CONSTANTS.Kn * amount; + return chroma.lab(lab).alpha(me.alpha()); + }; + + Color.prototype.brighten = function(amount) { + if (amount == null) { + amount = 1; + } + return this.darken(-amount); + }; + + Color.prototype.darker = Color.prototype.darken; + + Color.prototype.brighter = Color.prototype.brighten; + + Color.prototype.saturate = function(amount) { + var lch, me; + if (amount == null) { + amount = 1; + } + me = this; + lch = me.lch(); + lch[1] += amount * LAB_CONSTANTS.Kn; + if (lch[1] < 0) { + lch[1] = 0; + } + return chroma.lch(lch).alpha(me.alpha()); + }; + + Color.prototype.desaturate = function(amount) { + if (amount == null) { + amount = 1; + } + return this.saturate(-amount); + }; + + Color.prototype.premultiply = function() { + var a, rgb; + rgb = this.rgb(); + a = this.alpha(); + return chroma(rgb[0] * a, rgb[1] * a, rgb[2] * a, a); + }; + + blend = function(bottom, top, mode) { + if (!blend[mode]) { + throw 'unknown blend mode ' + mode; + } + return blend[mode](bottom, top); + }; + + blend_f = function(f) { + return function(bottom, top) { + var c0, c1; + c0 = chroma(top).rgb(); + c1 = chroma(bottom).rgb(); + return chroma(f(c0, c1), 'rgb'); + }; + }; + + each = function(f) { + return function(c0, c1) { + var i, o, out; + out = []; + for (i = o = 0; o <= 3; i = ++o) { + out[i] = f(c0[i], c1[i]); + } + return out; + }; + }; + + normal = function(a, b) { + return a; + }; + + multiply = function(a, b) { + return a * b / 255; + }; + + darken = function(a, b) { + if (a > b) { + return b; + } else { + return a; + } + }; + + lighten = function(a, b) { + if (a > b) { + return a; + } else { + return b; + } + }; + + screen = function(a, b) { + return 255 * (1 - (1 - a / 255) * (1 - b / 255)); + }; + + overlay = function(a, b) { + if (b < 128) { + return 2 * a * b / 255; + } else { + return 255 * (1 - 2 * (1 - a / 255) * (1 - b / 255)); + } + }; + + burn = function(a, b) { + return 255 * (1 - (1 - b / 255) / (a / 255)); + }; + + dodge = function(a, b) { + if (a === 255) { + return 255; + } + a = 255 * (b / 255) / (1 - a / 255); + if (a > 255) { + return 255; + } else { + return a; + } + }; + + blend.normal = blend_f(each(normal)); + + blend.multiply = blend_f(each(multiply)); + + blend.screen = blend_f(each(screen)); + + blend.overlay = blend_f(each(overlay)); + + blend.darken = blend_f(each(darken)); + + blend.lighten = blend_f(each(lighten)); + + blend.dodge = blend_f(each(dodge)); + + blend.burn = blend_f(each(burn)); + + chroma.blend = blend; + + chroma.analyze = function(data) { + var len, o, r, val; + r = { + min: Number.MAX_VALUE, + max: Number.MAX_VALUE * -1, + sum: 0, + values: [], + count: 0 + }; + for (o = 0, len = data.length; o < len; o++) { + val = data[o]; + if ((val != null) && !isNaN(val)) { + r.values.push(val); + r.sum += val; + if (val < r.min) { + r.min = val; + } + if (val > r.max) { + r.max = val; + } + r.count += 1; + } + } + r.domain = [r.min, r.max]; + r.limits = function(mode, num) { + return chroma.limits(r, mode, num); + }; + return r; + }; + + chroma.scale = function(colors, positions) { + var _classes, _colorCache, _colors, _correctLightness, _domain, _fixed, _max, _min, _mode, _nacol, _out, _padding, _pos, _spread, classifyValue, f, getClass, getColor, resetCache, setColors, tmap; + _mode = 'rgb'; + _nacol = chroma('#ccc'); + _spread = 0; + _fixed = false; + _domain = [0, 1]; + _pos = []; + _padding = [0, 0]; + _classes = false; + _colors = []; + _out = false; + _min = 0; + _max = 1; + _correctLightness = false; + _colorCache = {}; + setColors = function(colors) { + var c, col, o, ref, ref1, ref2, w; + if (colors == null) { + colors = ['#fff', '#000']; + } + if ((colors != null) && type(colors) === 'string' && (((ref = chroma.brewer) != null ? ref[colors] : void 0) != null)) { + colors = chroma.brewer[colors]; + } + if (type(colors) === 'array') { + colors = colors.slice(0); + for (c = o = 0, ref1 = colors.length - 1; 0 <= ref1 ? o <= ref1 : o >= ref1; c = 0 <= ref1 ? ++o : --o) { + col = colors[c]; + if (type(col) === "string") { + colors[c] = chroma(col); + } + } + _pos.length = 0; + for (c = w = 0, ref2 = colors.length - 1; 0 <= ref2 ? w <= ref2 : w >= ref2; c = 0 <= ref2 ? ++w : --w) { + _pos.push(c / (colors.length - 1)); + } + } + resetCache(); + return _colors = colors; + }; + getClass = function(value) { + var i, n; + if (_classes != null) { + n = _classes.length - 1; + i = 0; + while (i < n && value >= _classes[i]) { + i++; + } + return i - 1; + } + return 0; + }; + tmap = function(t) { + return t; + }; + classifyValue = function(value) { + var i, maxc, minc, n, val; + val = value; + if (_classes.length > 2) { + n = _classes.length - 1; + i = getClass(value); + minc = _classes[0] + (_classes[1] - _classes[0]) * (0 + _spread * 0.5); + maxc = _classes[n - 1] + (_classes[n] - _classes[n - 1]) * (1 - _spread * 0.5); + val = _min + ((_classes[i] + (_classes[i + 1] - _classes[i]) * 0.5 - minc) / (maxc - minc)) * (_max - _min); + } + return val; + }; + getColor = function(val, bypassMap) { + var c, col, i, k, o, p, ref, t; + if (bypassMap == null) { + bypassMap = false; + } + if (isNaN(val)) { + return _nacol; + } + if (!bypassMap) { + if (_classes && _classes.length > 2) { + c = getClass(val); + t = c / (_classes.length - 2); + t = _padding[0] + (t * (1 - _padding[0] - _padding[1])); + } else if (_max !== _min) { + t = (val - _min) / (_max - _min); + t = _padding[0] + (t * (1 - _padding[0] - _padding[1])); + t = Math.min(1, Math.max(0, t)); + } else { + t = 1; + } + } else { + t = val; + } + if (!bypassMap) { + t = tmap(t); + } + k = Math.floor(t * 10000); + if (_colorCache[k]) { + col = _colorCache[k]; + } else { + if (type(_colors) === 'array') { + for (i = o = 0, ref = _pos.length - 1; 0 <= ref ? o <= ref : o >= ref; i = 0 <= ref ? ++o : --o) { + p = _pos[i]; + if (t <= p) { + col = _colors[i]; + break; + } + if (t >= p && i === _pos.length - 1) { + col = _colors[i]; + break; + } + if (t > p && t < _pos[i + 1]) { + t = (t - p) / (_pos[i + 1] - p); + col = chroma.interpolate(_colors[i], _colors[i + 1], t, _mode); + break; + } + } + } else if (type(_colors) === 'function') { + col = _colors(t); + } + _colorCache[k] = col; + } + return col; + }; + resetCache = function() { + return _colorCache = {}; + }; + setColors(colors); + f = function(v) { + var c; + c = chroma(getColor(v)); + if (_out && c[_out]) { + return c[_out](); + } else { + return c; + } + }; + f.classes = function(classes) { + var d; + if (classes != null) { + if (type(classes) === 'array') { + _classes = classes; + _domain = [classes[0], classes[classes.length - 1]]; + } else { + d = chroma.analyze(_domain); + if (classes === 0) { + _classes = [d.min, d.max]; + } else { + _classes = chroma.limits(d, 'e', classes); + } + } + return f; + } + return _classes; + }; + f.domain = function(domain) { + var c, d, k, len, o, ref, w; + if (!arguments.length) { + return _domain; + } + _min = domain[0]; + _max = domain[domain.length - 1]; + _pos = []; + k = _colors.length; + if (domain.length === k && _min !== _max) { + for (o = 0, len = domain.length; o < len; o++) { + d = domain[o]; + _pos.push((d - _min) / (_max - _min)); + } + } else { + for (c = w = 0, ref = k - 1; 0 <= ref ? w <= ref : w >= ref; c = 0 <= ref ? ++w : --w) { + _pos.push(c / (k - 1)); + } + } + _domain = [_min, _max]; + return f; + }; + f.mode = function(_m) { + if (!arguments.length) { + return _mode; + } + _mode = _m; + resetCache(); + return f; + }; + f.range = function(colors, _pos) { + setColors(colors, _pos); + return f; + }; + f.out = function(_o) { + _out = _o; + return f; + }; + f.spread = function(val) { + if (!arguments.length) { + return _spread; + } + _spread = val; + return f; + }; + f.correctLightness = function(v) { + if (v == null) { + v = true; + } + _correctLightness = v; + resetCache(); + if (_correctLightness) { + tmap = function(t) { + var L0, L1, L_actual, L_diff, L_ideal, max_iter, pol, t0, t1; + L0 = getColor(0, true).lab()[0]; + L1 = getColor(1, true).lab()[0]; + pol = L0 > L1; + L_actual = getColor(t, true).lab()[0]; + L_ideal = L0 + (L1 - L0) * t; + L_diff = L_actual - L_ideal; + t0 = 0; + t1 = 1; + max_iter = 20; + while (Math.abs(L_diff) > 1e-2 && max_iter-- > 0) { + (function() { + if (pol) { + L_diff *= -1; + } + if (L_diff < 0) { + t0 = t; + t += (t1 - t) * 0.5; + } else { + t1 = t; + t += (t0 - t) * 0.5; + } + L_actual = getColor(t, true).lab()[0]; + return L_diff = L_actual - L_ideal; + })(); + } + return t; + }; + } else { + tmap = function(t) { + return t; + }; + } + return f; + }; + f.padding = function(p) { + if (p != null) { + if (type(p) === 'number') { + p = [p, p]; + } + _padding = p; + return f; + } else { + return _padding; + } + }; + f.colors = function() { + var dd, dm, i, numColors, o, out, ref, results, samples, w; + numColors = 0; + out = 'hex'; + if (arguments.length === 1) { + if (type(arguments[0]) === 'string') { + out = arguments[0]; + } else { + numColors = arguments[0]; + } + } + if (arguments.length === 2) { + numColors = arguments[0], out = arguments[1]; + } + if (numColors) { + dm = _domain[0]; + dd = _domain[1] - dm; + return (function() { + results = []; + for (var o = 0; 0 <= numColors ? o < numColors : o > numColors; 0 <= numColors ? o++ : o--){ results.push(o); } + return results; + }).apply(this).map(function(i) { + return f(dm + i / (numColors - 1) * dd)[out](); + }); + } + colors = []; + samples = []; + if (_classes && _classes.length > 2) { + for (i = w = 1, ref = _classes.length; 1 <= ref ? w < ref : w > ref; i = 1 <= ref ? ++w : --w) { + samples.push((_classes[i - 1] + _classes[i]) * 0.5); + } + } else { + samples = _domain; + } + return samples.map(function(v) { + return f(v)[out](); + }); + }; + return f; + }; + + if (chroma.scales == null) { + chroma.scales = {}; + } + + chroma.scales.cool = function() { + return chroma.scale([chroma.hsl(180, 1, .9), chroma.hsl(250, .7, .4)]); + }; + + chroma.scales.hot = function() { + return chroma.scale(['#000', '#f00', '#ff0', '#fff'], [0, .25, .75, 1]).mode('rgb'); + }; + + chroma.analyze = function(data, key, filter) { + var add, k, len, o, r, val, visit; + r = { + min: Number.MAX_VALUE, + max: Number.MAX_VALUE * -1, + sum: 0, + values: [], + count: 0 + }; + if (filter == null) { + filter = function() { + return true; + }; + } + add = function(val) { + if ((val != null) && !isNaN(val)) { + r.values.push(val); + r.sum += val; + if (val < r.min) { + r.min = val; + } + if (val > r.max) { + r.max = val; + } + r.count += 1; + } + }; + visit = function(val, k) { + if (filter(val, k)) { + if ((key != null) && type(key) === 'function') { + return add(key(val)); + } else if ((key != null) && type(key) === 'string' || type(key) === 'number') { + return add(val[key]); + } else { + return add(val); + } + } + }; + if (type(data) === 'array') { + for (o = 0, len = data.length; o < len; o++) { + val = data[o]; + visit(val); + } + } else { + for (k in data) { + val = data[k]; + visit(val, k); + } + } + r.domain = [r.min, r.max]; + r.limits = function(mode, num) { + return chroma.limits(r, mode, num); + }; + return r; + }; + + chroma.limits = function(data, mode, num) { + var aa, ab, ac, ad, ae, af, ag, ah, ai, aj, ak, al, am, assignments, best, centroids, cluster, clusterSizes, dist, i, j, kClusters, limits, max_log, min, min_log, mindist, n, nb_iters, newCentroids, o, p, pb, pr, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, repeat, sum, tmpKMeansBreaks, value, values, w; + if (mode == null) { + mode = 'equal'; + } + if (num == null) { + num = 7; + } + if (type(data) === 'array') { + data = chroma.analyze(data); + } + min = data.min; + max = data.max; + sum = data.sum; + values = data.values.sort(function(a, b) { + return a - b; + }); + limits = []; + if (mode.substr(0, 1) === 'c') { + limits.push(min); + limits.push(max); + } + if (mode.substr(0, 1) === 'e') { + limits.push(min); + for (i = o = 1, ref = num - 1; 1 <= ref ? o <= ref : o >= ref; i = 1 <= ref ? ++o : --o) { + limits.push(min + (i / num) * (max - min)); + } + limits.push(max); + } else if (mode.substr(0, 1) === 'l') { + if (min <= 0) { + throw 'Logarithmic scales are only possible for values > 0'; + } + min_log = Math.LOG10E * log(min); + max_log = Math.LOG10E * log(max); + limits.push(min); + for (i = w = 1, ref1 = num - 1; 1 <= ref1 ? w <= ref1 : w >= ref1; i = 1 <= ref1 ? ++w : --w) { + limits.push(pow(10, min_log + (i / num) * (max_log - min_log))); + } + limits.push(max); + } else if (mode.substr(0, 1) === 'q') { + limits.push(min); + for (i = aa = 1, ref2 = num - 1; 1 <= ref2 ? aa <= ref2 : aa >= ref2; i = 1 <= ref2 ? ++aa : --aa) { + p = values.length * i / num; + pb = floor(p); + if (pb === p) { + limits.push(values[pb]); + } else { + pr = p - pb; + limits.push(values[pb] * pr + values[pb + 1] * (1 - pr)); + } + } + limits.push(max); + } else if (mode.substr(0, 1) === 'k') { + + /* + implementation based on + http://code.google.com/p/figue/source/browse/trunk/figue.js#336 + simplified for 1-d input values + */ + n = values.length; + assignments = new Array(n); + clusterSizes = new Array(num); + repeat = true; + nb_iters = 0; + centroids = null; + centroids = []; + centroids.push(min); + for (i = ab = 1, ref3 = num - 1; 1 <= ref3 ? ab <= ref3 : ab >= ref3; i = 1 <= ref3 ? ++ab : --ab) { + centroids.push(min + (i / num) * (max - min)); + } + centroids.push(max); + while (repeat) { + for (j = ac = 0, ref4 = num - 1; 0 <= ref4 ? ac <= ref4 : ac >= ref4; j = 0 <= ref4 ? ++ac : --ac) { + clusterSizes[j] = 0; + } + for (i = ad = 0, ref5 = n - 1; 0 <= ref5 ? ad <= ref5 : ad >= ref5; i = 0 <= ref5 ? ++ad : --ad) { + value = values[i]; + mindist = Number.MAX_VALUE; + for (j = ae = 0, ref6 = num - 1; 0 <= ref6 ? ae <= ref6 : ae >= ref6; j = 0 <= ref6 ? ++ae : --ae) { + dist = abs(centroids[j] - value); + if (dist < mindist) { + mindist = dist; + best = j; + } + } + clusterSizes[best]++; + assignments[i] = best; + } + newCentroids = new Array(num); + for (j = af = 0, ref7 = num - 1; 0 <= ref7 ? af <= ref7 : af >= ref7; j = 0 <= ref7 ? ++af : --af) { + newCentroids[j] = null; + } + for (i = ag = 0, ref8 = n - 1; 0 <= ref8 ? ag <= ref8 : ag >= ref8; i = 0 <= ref8 ? ++ag : --ag) { + cluster = assignments[i]; + if (newCentroids[cluster] === null) { + newCentroids[cluster] = values[i]; + } else { + newCentroids[cluster] += values[i]; + } + } + for (j = ah = 0, ref9 = num - 1; 0 <= ref9 ? ah <= ref9 : ah >= ref9; j = 0 <= ref9 ? ++ah : --ah) { + newCentroids[j] *= 1 / clusterSizes[j]; + } + repeat = false; + for (j = ai = 0, ref10 = num - 1; 0 <= ref10 ? ai <= ref10 : ai >= ref10; j = 0 <= ref10 ? ++ai : --ai) { + if (newCentroids[j] !== centroids[i]) { + repeat = true; + break; + } + } + centroids = newCentroids; + nb_iters++; + if (nb_iters > 200) { + repeat = false; + } + } + kClusters = {}; + for (j = aj = 0, ref11 = num - 1; 0 <= ref11 ? aj <= ref11 : aj >= ref11; j = 0 <= ref11 ? ++aj : --aj) { + kClusters[j] = []; + } + for (i = ak = 0, ref12 = n - 1; 0 <= ref12 ? ak <= ref12 : ak >= ref12; i = 0 <= ref12 ? ++ak : --ak) { + cluster = assignments[i]; + kClusters[cluster].push(values[i]); + } + tmpKMeansBreaks = []; + for (j = al = 0, ref13 = num - 1; 0 <= ref13 ? al <= ref13 : al >= ref13; j = 0 <= ref13 ? ++al : --al) { + tmpKMeansBreaks.push(kClusters[j][0]); + tmpKMeansBreaks.push(kClusters[j][kClusters[j].length - 1]); + } + tmpKMeansBreaks = tmpKMeansBreaks.sort(function(a, b) { + return a - b; + }); + limits.push(tmpKMeansBreaks[0]); + for (i = am = 1, ref14 = tmpKMeansBreaks.length - 1; am <= ref14; i = am += 2) { + if (!isNaN(tmpKMeansBreaks[i])) { + limits.push(tmpKMeansBreaks[i]); + } + } + } + return limits; + }; + + hsi2rgb = function(h, s, i) { + + /* + borrowed from here: + http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/hsi2rgb.cpp + */ + var args, b, g, r; + args = unpack(arguments); + h = args[0], s = args[1], i = args[2]; + h /= 360; + if (h < 1 / 3) { + b = (1 - s) / 3; + r = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + g = 1 - (b + r); + } else if (h < 2 / 3) { + h -= 1 / 3; + r = (1 - s) / 3; + g = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + b = 1 - (r + g); + } else { + h -= 2 / 3; + g = (1 - s) / 3; + b = (1 + s * cos(TWOPI * h) / cos(PITHIRD - TWOPI * h)) / 3; + r = 1 - (g + b); + } + r = limit(i * r * 3); + g = limit(i * g * 3); + b = limit(i * b * 3); + return [r * 255, g * 255, b * 255, args.length > 3 ? args[3] : 1]; + }; + + rgb2hsi = function() { + + /* + borrowed from here: + http://hummer.stanford.edu/museinfo/doc/examples/humdrum/keyscape2/rgb2hsi.cpp + */ + var b, g, h, i, min, r, ref, s; + ref = unpack(arguments), r = ref[0], g = ref[1], b = ref[2]; + TWOPI = Math.PI * 2; + r /= 255; + g /= 255; + b /= 255; + min = Math.min(r, g, b); + i = (r + g + b) / 3; + s = 1 - min / i; + if (s === 0) { + h = 0; + } else { + h = ((r - g) + (r - b)) / 2; + h /= Math.sqrt((r - g) * (r - g) + (r - b) * (g - b)); + h = Math.acos(h); + if (b > g) { + h = TWOPI - h; + } + h /= TWOPI; + } + return [h * 360, s, i]; + }; + + chroma.hsi = function() { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args); + return Object(result) === result ? result : child; + })(Color, slice.call(arguments).concat(['hsi']), function(){}); + }; + + _input.hsi = hsi2rgb; + + Color.prototype.hsi = function() { + return rgb2hsi(this._rgb); + }; + + interpolate_hsx = function(col1, col2, f, m) { + var dh, hue, hue0, hue1, lbv, lbv0, lbv1, res, sat, sat0, sat1, xyz0, xyz1; + if (m === 'hsl') { + xyz0 = col1.hsl(); + xyz1 = col2.hsl(); + } else if (m === 'hsv') { + xyz0 = col1.hsv(); + xyz1 = col2.hsv(); + } else if (m === 'hsi') { + xyz0 = col1.hsi(); + xyz1 = col2.hsi(); + } else if (m === 'lch' || m === 'hcl') { + m = 'hcl'; + xyz0 = col1.hcl(); + xyz1 = col2.hcl(); + } + if (m.substr(0, 1) === 'h') { + hue0 = xyz0[0], sat0 = xyz0[1], lbv0 = xyz0[2]; + hue1 = xyz1[0], sat1 = xyz1[1], lbv1 = xyz1[2]; + } + if (!isNaN(hue0) && !isNaN(hue1)) { + if (hue1 > hue0 && hue1 - hue0 > 180) { + dh = hue1 - (hue0 + 360); + } else if (hue1 < hue0 && hue0 - hue1 > 180) { + dh = hue1 + 360 - hue0; + } else { + dh = hue1 - hue0; + } + hue = hue0 + f * dh; + } else if (!isNaN(hue0)) { + hue = hue0; + if ((lbv1 === 1 || lbv1 === 0) && m !== 'hsv') { + sat = sat0; + } + } else if (!isNaN(hue1)) { + hue = hue1; + if ((lbv0 === 1 || lbv0 === 0) && m !== 'hsv') { + sat = sat1; + } + } else { + hue = Number.NaN; + } + if (sat == null) { + sat = sat0 + f * (sat1 - sat0); + } + lbv = lbv0 + f * (lbv1 - lbv0); + return res = chroma[m](hue, sat, lbv); + }; + + _interpolators = _interpolators.concat((function() { + var len, o, ref, results; + ref = ['hsv', 'hsl', 'hsi', 'hcl', 'lch']; + results = []; + for (o = 0, len = ref.length; o < len; o++) { + m = ref[o]; + results.push([m, interpolate_hsx]); + } + return results; + })()); + + interpolate_num = function(col1, col2, f, m) { + var n1, n2; + n1 = col1.num(); + n2 = col2.num(); + return chroma.num(n1 + (n2 - n1) * f, 'num'); + }; + + _interpolators.push(['num', interpolate_num]); + + interpolate_lab = function(col1, col2, f, m) { + var res, xyz0, xyz1; + xyz0 = col1.lab(); + xyz1 = col2.lab(); + return res = new Color(xyz0[0] + f * (xyz1[0] - xyz0[0]), xyz0[1] + f * (xyz1[1] - xyz0[1]), xyz0[2] + f * (xyz1[2] - xyz0[2]), m); + }; + + _interpolators.push(['lab', interpolate_lab]); + +}).call(this); diff --git a/mdot/mdot_server/mdot_server/app/lib/jquery.js b/mdot/mdot_server/mdot_server/app/lib/jquery.js new file mode 100644 index 0000000..3854747 --- /dev/null +++ b/mdot/mdot_server/mdot_server/app/lib/jquery.js @@ -0,0 +1,9842 @@ +/*! + * jQuery JavaScript Library v2.2.3 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-04-05T19:26Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Support: Firefox 18+ +// Can't be in strict mode, several libs including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +//"use strict"; +var arr = []; + +var document = window.document; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "2.2.3", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + var realStringObj = obj && obj.toString(); + return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; + }, + + isPlainObject: function( obj ) { + var key; + + // Not plain objects: + // - Any object or value whose internal [[Class]] property is not "[object Object]" + // - DOM nodes + // - window + if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call( obj, "constructor" ) && + !hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android<4.0, iOS<6 (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + var script, + indirect = eval; + + code = jQuery.trim( code ); + + if ( code ) { + + // If the code includes a valid, prologue position + // strict mode pragma, execute code by injecting a + // script tag into the document. + if ( code.indexOf( "use strict" ) === 1 ) { + script = document.createElement( "script" ); + script.text = code; + document.head.appendChild( script ).parentNode.removeChild( script ); + } else { + + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + + indirect( code ); + } + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE9-11+ + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android<4.1 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +// JSHint would error on this code due to the Symbol not being defined in ES5. +// Defining this global in .jshintrc would create a danger of using the global +// unguarded in another place, it seems safer to just disable JSHint for these +// three lines. +/* jshint ignore: start */ +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} +/* jshint ignore: end */ + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: iOS 8.2 (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.2.1 + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2015-10-17 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // http://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, nidselect, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; + while ( i-- ) { + groups[i] = nidselect + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, parent, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( (parent = document.defaultView) && parent.top !== parent ) { + // Support: IE 11 + if ( parent.addEventListener ) { + parent.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + return m ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + docElem.appendChild( div ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibing-combinator selector` fails + if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + 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; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( (oldCache = uniqueCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + } ); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, + len = this.length, + ret = [], + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + // Support: Blackberry 4.6 + // gEBID returns nodes no longer in the document (#6963) + if ( elem && elem.parentNode ) { + + // Inject the element directly into the jQuery object + this.length = 1; + this[ 0 ] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( pos ? + pos.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnotwhite = ( /\S+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], + [ "notify", "progress", jQuery.Callbacks( "memory" ) ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this === promise ? newDefer.promise() : this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( function() { + + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || + ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. + // If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // Add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .progress( updateFunc( i, progressContexts, progressValues ) ) + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ); + } else { + --remaining; + } + } + } + + // If we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +} ); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +} ); + +/** + * The ready event handler and self cleanup method + */ +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called + // after the browser event has already occurred. + // Support: IE9-10 only + // Older IE sometimes signals "interactive" too soon + if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + + } else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + /* jshint -W018 */ + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + register: function( owner, initial ) { + var value = initial || {}; + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable, non-writable property + // configurability must be true to allow the property to be + // deleted with the delete operator + } else { + Object.defineProperty( owner, this.expando, { + value: value, + writable: true, + configurable: true + } ); + } + return owner[ this.expando ]; + }, + cache: function( owner ) { + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( !acceptData( owner ) ) { + return {}; + } + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + if ( typeof data === "string" ) { + cache[ data ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ prop ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + owner[ this.expando ] && owner[ this.expando ][ key ]; + }, + access: function( owner, key, value ) { + var stored; + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + stored = this.get( owner, key ); + + return stored !== undefined ? + stored : this.get( owner, jQuery.camelCase( key ) ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, name, camel, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key === undefined ) { + this.register( owner ); + + } else { + + // Support array or space separated string of keys + if ( jQuery.isArray( key ) ) { + + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = key.concat( key.map( jQuery.camelCase ) ); + } else { + camel = jQuery.camelCase( key ); + + // Try the string as a key before any manipulation + if ( key in cache ) { + name = [ key, camel ]; + } else { + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + name = camel; + name = name in cache ? + [ name ] : ( name.match( rnotwhite ) || [] ); + } + } + + i = name.length; + + while ( i-- ) { + delete cache[ name[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <= 35-45+ + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://code.google.com/p/chromium/issues/detail?id=378607 + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data, camelKey; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // with the key as-is + data = dataUser.get( elem, key ) || + + // Try to find dashed key if it exists (gh-2779) + // This is for 2.2.x only + dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); + + if ( data !== undefined ) { + return data; + } + + camelKey = jQuery.camelCase( key ); + + // Attempt to get data from the cache + // with the key camelized + data = dataUser.get( elem, camelKey ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, camelKey, undefined ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + camelKey = jQuery.camelCase( key ); + this.each( function() { + + // First, attempt to store a copy or reference of any + // data that might've been store with a camelCased key. + var data = dataUser.get( this, camelKey ); + + // For HTML5 data-* attribute interop, we have to + // store property names with dashes in a camelCase form. + // This might not apply to all properties...* + dataUser.set( this, camelKey, value ); + + // *... In the case of properties that might _actually_ + // have dashes, we need to also store a copy of that + // unchanged property. + if ( key.indexOf( "-" ) > -1 && data !== undefined ) { + dataUser.set( this, key, value ); + } + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || + !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { return tween.cur(); } : + function() { return jQuery.css( elem, prop, "" ); }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([\w:-]+)/ ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE9 + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE9-11+ + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0-4.3, Safari<=5.1 + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari<=5.1, Android<4.2 + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<=11+ + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE9 +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support (at least): Chrome, IE9 + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // + // Support: Firefox<=42+ + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + + "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split( " " ), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " + + "screenX screenY toElement" ).split( " " ), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: Cordova 2.5 (WebKit) (#13255) + // All events should have a target; Cordova deviceready doesn't + if ( !event.target ) { + event.target = document; + } + + // Support: Safari 6.0+, Chrome<28 + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android<4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://code.google.com/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/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 && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + + // Support: IE 10-11, Edge 10240+ + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName( "tbody" )[ 0 ] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <= 35-45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <= 35-45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + + // Keep domManip exposed until 3.0 (gh-2225) + domManip: domManip, + + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: QtWebKit + // .get() because push.apply(_, arraylike) throws + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); + + +var iframe, + elemdisplay = { + + // Support: Firefox + // We have to pre-define these values for FF (#10227) + HTML: "block", + BODY: "block" + }; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ + +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + display = jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = ( iframe || jQuery( "