From 74afe433fb1f7c5c9eda5a6c9f8e55ceb615abe5 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 13:28:15 +0200 Subject: [PATCH 1/8] Add weather modules. --- config.codekit | 2034 ----------------- config/{config.js => config.js.sample} | 18 +- css/main.css | 18 +- js/defaults.js | 1 + js/loader.js | 1 + js/main.js | 25 +- modules/clock/clock.js | 2 +- modules/currentweather/currentweather.css | 9 + modules/currentweather/currentweather.js | 271 +++ modules/helper_test/node_helper.js | 2 - modules/weatherforecast/weatherforecast.css | 18 + modules/weatherforecast/weatherforecast.js | 263 +++ vendor/vendor.js | 1 + vendor/weather-icons/weather-icons.css | 327 +++ .../weathericons-regular-webfont.eot | Bin 0 -> 28904 bytes .../weathericons-regular-webfont.svg | 121 + .../weathericons-regular-webfont.ttf | Bin 0 -> 50368 bytes .../weathericons-regular-webfont.woff | Bin 0 -> 32396 bytes 18 files changed, 1064 insertions(+), 2047 deletions(-) delete mode 100644 config.codekit rename config/{config.js => config.js.sample} (53%) create mode 100644 modules/currentweather/currentweather.css create mode 100644 modules/currentweather/currentweather.js delete mode 100644 modules/helper_test/node_helper.js create mode 100644 modules/weatherforecast/weatherforecast.css create mode 100644 modules/weatherforecast/weatherforecast.js create mode 100755 vendor/weather-icons/weather-icons.css create mode 100755 vendor/weather-icons/weathericons-regular-webfont.eot create mode 100755 vendor/weather-icons/weathericons-regular-webfont.svg create mode 100755 vendor/weather-icons/weathericons-regular-webfont.ttf create mode 100755 vendor/weather-icons/weathericons-regular-webfont.woff diff --git a/config.codekit b/config.codekit deleted file mode 100644 index 62ffb346..00000000 --- a/config.codekit +++ /dev/null @@ -1,2034 +0,0 @@ -{ -"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit", -"creatorBuild": "19115", -"files": { - "\/config\/config.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/config\/config.js", - "outputAbbreviatedPath": "\/config\/min\/config-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/css\/main.css": { - "fileType": 16, - "ignore": 1, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/css\/main.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/robot.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/robot.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_black\/Roboto-Black-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/Roboto-Black-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_black\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_black\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_black\/specimen_files\/Roboto-Black-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 83352, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/Roboto-Black-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/Roboto-Black-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_black\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_black\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_black\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_blackitalic\/Roboto-BlackItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/Roboto-BlackItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_blackitalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_blackitalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_blackitalic\/specimen_files\/Roboto-BlackItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 87438, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/Roboto-BlackItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/Roboto-BlackItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_blackitalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_blackitalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_blackitalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bold\/Roboto-Bold-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/Roboto-Bold-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bold\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_bold\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bold\/specimen_files\/Roboto-Bold-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 85781, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/Roboto-Bold-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/Roboto-Bold-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_bold\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bold\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bold\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondensed\/RobotoCondensed-Bold-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/RobotoCondensed-Bold-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondensed\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_boldcondensed\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondensed\/specimen_files\/RobotoCondensed-Bold-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 86782, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/RobotoCondensed-Bold-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/RobotoCondensed-Bold-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_boldcondensed\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondensed\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondensed\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondenseditalic\/RobotoCondensed-BoldItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/RobotoCondensed-BoldItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/RobotoCondensed-BoldItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 91094, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/RobotoCondensed-BoldItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/RobotoCondensed-BoldItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_boldcondenseditalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_boldcondenseditalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bolditalic\/Roboto-BoldItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/Roboto-BoldItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bolditalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_bolditalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bolditalic\/specimen_files\/Roboto-BoldItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 89575, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/Roboto-BoldItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/Roboto-BoldItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_bolditalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_bolditalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_bolditalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condensed\/RobotoCondensed-Regular-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/RobotoCondensed-Regular-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condensed\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_condensed\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condensed\/specimen_files\/RobotoCondensed-Regular-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 90523, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/RobotoCondensed-Regular-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/RobotoCondensed-Regular-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_condensed\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condensed\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condensed\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condenseditalic\/RobotoCondensed-Italic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/RobotoCondensed-Italic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condenseditalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_condenseditalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condenseditalic\/specimen_files\/RobotoCondensed-Italic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 93738, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/RobotoCondensed-Italic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/RobotoCondensed-Italic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_condenseditalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_condenseditalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_condenseditalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_italic\/Roboto-Italic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/Roboto-Italic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_italic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_italic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_italic\/specimen_files\/Roboto-Italic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 89124, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/Roboto-Italic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/Roboto-Italic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_italic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_italic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_italic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_light\/Roboto-Light-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/Roboto-Light-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_light\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_light\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_light\/specimen_files\/Roboto-Light-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 83980, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/Roboto-Light-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/Roboto-Light-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_light\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_light\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_light\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondensed\/RobotoCondensed-Light-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/RobotoCondensed-Light-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondensed\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_lightcondensed\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondensed\/specimen_files\/RobotoCondensed-Light-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 89201, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/RobotoCondensed-Light-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/RobotoCondensed-Light-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_lightcondensed\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondensed\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondensed\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondenseditalic\/RobotoCondensed-LightItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/RobotoCondensed-LightItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/RobotoCondensed-LightItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 92532, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/RobotoCondensed-LightItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/RobotoCondensed-LightItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightcondenseditalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightcondenseditalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightitalic\/Roboto-LightItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/Roboto-LightItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightitalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_lightitalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightitalic\/specimen_files\/Roboto-LightItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 88922, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/Roboto-LightItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/Roboto-LightItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_lightitalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_lightitalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_lightitalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_medium\/Roboto-Medium-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/Roboto-Medium-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_medium\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_medium\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_medium\/specimen_files\/Roboto-Medium-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 86670, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/Roboto-Medium-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/Roboto-Medium-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_medium\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_medium\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_medium\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_mediumitalic\/Roboto-MediumItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/Roboto-MediumItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_mediumitalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_mediumitalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_mediumitalic\/specimen_files\/Roboto-MediumItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 89781, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/Roboto-MediumItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/Roboto-MediumItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_mediumitalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_mediumitalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_mediumitalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_regular\/Roboto-Regular-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/Roboto-Regular-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_regular\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_regular\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_regular\/specimen_files\/Roboto-Regular-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 85569, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/Roboto-Regular-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/Roboto-Regular-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_regular\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_regular\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_regular\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thin\/Roboto-Thin-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/Roboto-Thin-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thin\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_thin\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thin\/specimen_files\/Roboto-Thin-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 80640, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/Roboto-Thin-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/Roboto-Thin-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_thin\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thin\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thin\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thinitalic\/Roboto-ThinItalic-demo.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/Roboto-ThinItalic-demo.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thinitalic\/specimen_files\/easytabs.js": { - "fileType": 64, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/easytabs.js", - "outputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/min\/easytabs-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/fonts\/roboto_thinitalic\/specimen_files\/grid_12-825-55-15.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/grid_12-825-55-15.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thinitalic\/specimen_files\/Roboto-ThinItalic-cleartype.png": { - "fileType": 32768, - "ignore": 0, - "ignoreWasSetByUser": 0, - "initialSize": 83107, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/Roboto-ThinItalic-cleartype.png", - "outputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/Roboto-ThinItalic-cleartype.png", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "processed": 0 - }, - "\/fonts\/roboto_thinitalic\/specimen_files\/specimen_stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/specimen_files\/specimen_stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/fonts\/roboto_thinitalic\/stylesheet.css": { - "fileType": 16, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/fonts\/roboto_thinitalic\/stylesheet.css", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/index.html": { - "fileType": 8192, - "ignore": 0, - "ignoreWasSetByUser": 0, - "inputAbbreviatedPath": "\/index.html", - "outputAbbreviatedPath": "No Output Path", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0 - }, - "\/js\/class.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/class.js", - "outputAbbreviatedPath": "\/js\/min\/class-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/js\/defaults.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/defaults.js", - "outputAbbreviatedPath": "\/js\/min\/defaults-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/js\/loader.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/loader.js", - "outputAbbreviatedPath": "\/js\/min\/loader-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/js\/logger.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/logger.js", - "outputAbbreviatedPath": "\/js\/min\/logger-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/js\/main.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/main.js", - "outputAbbreviatedPath": "\/js\/min\/main-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 0, - "syntaxCheckerStyle": 1 - }, - "\/js\/module.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/js\/module.js", - "outputAbbreviatedPath": "\/js\/min\/module-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/modules\/clock\/clock.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/modules\/clock\/clock.js", - "outputAbbreviatedPath": "\/modules\/clock\/min\/clock-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/modules\/compliments\/compliments.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/modules\/compliments\/compliments.js", - "outputAbbreviatedPath": "\/modules\/compliments\/min\/compliments-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/modules\/helloworld\/helloworld.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/modules\/helloworld\/helloworld.js", - "outputAbbreviatedPath": "\/modules\/helloworld\/min\/helloworld-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/vendor\/moment\/moment-with-locales.min.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/vendor\/moment\/moment-with-locales.min.js", - "outputAbbreviatedPath": "\/vendor\/moment\/min\/moment-with-locales.min-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - }, - "\/vendor\/vendor.js": { - "fileType": 64, - "ignore": 1, - "ignoreWasSetByUser": 1, - "inputAbbreviatedPath": "\/vendor\/vendor.js", - "outputAbbreviatedPath": "\/vendor\/min\/vendor-min.js", - "outputPathIsOutsideProject": 0, - "outputPathIsSetByUser": 0, - "outputStyle": 1, - "syntaxCheckerStyle": 1 - } - }, -"hooks": [ - ], -"lastSavedByUser": "Michael Teeuw", -"manualImportLinks": { - }, -"projectAttributes": { - "bowerAbbreviatedPath": "", - "displayValue": "MagicMirror V2", - "displayValueWasSetByUser": 1, - "iconImageName": "brackets_orange" - }, -"projectSettings": { - "alwaysUseExternalServer": 1, - "animateCSSInjections": 1, - "autoApplyPSLanguageSettingsStyle": 0, - "autoprefixerBrowserString": "> 1%, last 2 versions, Firefox ESR, Opera 12.1", - "autoSyncProjectSettingsFile": 1, - "browserRefreshDelay": 0, - "coffeeAutoOutputPathEnabled": 1, - "coffeeAutoOutputPathFilenamePattern": "*.js", - "coffeeAutoOutputPathRelativePath": "", - "coffeeAutoOutputPathReplace1": "", - "coffeeAutoOutputPathReplace2": "", - "coffeeAutoOutputPathStyle": 0, - "coffeeCreateSourceMap": 0, - "coffeeLintFlags2": { - "arrow_spacing": { - "active": 0, - "flagValue": -1 - }, - "camel_case_classes": { - "active": 1, - "flagValue": -1 - }, - "colon_assignment_spacing": { - "active": 0, - "flagValue": 1 - }, - "cyclomatic_complexity": { - "active": 0, - "flagValue": 10 - }, - "duplicate_key": { - "active": 1, - "flagValue": -1 - }, - "empty_constructor_needs_parens": { - "active": 0, - "flagValue": -1 - }, - "ensure_comprehensions": { - "active": 1, - "flagValue": -1 - }, - "indentation": { - "active": 1, - "flagValue": 2 - }, - "line_endings": { - "active": 0, - "flagValue": 0 - }, - "max_line_length": { - "active": 0, - "flagValue": 150 - }, - "missing_fat_arrows": { - "active": 0, - "flagValue": -1 - }, - "newlines_after_classes": { - "active": 0, - "flagValue": 3 - }, - "no_backticks": { - "active": 1, - "flagValue": -1 - }, - "no_debugger": { - "active": 1, - "flagValue": -1 - }, - "no_empty_functions": { - "active": 0, - "flagValue": -1 - }, - "no_empty_param_list": { - "active": 0, - "flagValue": -1 - }, - "no_implicit_braces": { - "active": 1, - "flagValue": -1 - }, - "no_implicit_parens": { - "active": 0, - "flagValue": -1 - }, - "no_interpolation_in_single_quotes": { - "active": 0, - "flagValue": -1 - }, - "no_nested_string_interpolation": { - "active": 1, - "flagValue": -1 - }, - "no_plusplus": { - "active": 0, - "flagValue": -1 - }, - "no_private_function_fat_arrows": { - "active": 1, - "flagValue": -1 - }, - "no_stand_alone_at": { - "active": 1, - "flagValue": -1 - }, - "no_tabs": { - "active": 1, - "flagValue": -1 - }, - "no_this": { - "active": 0, - "flagValue": -1 - }, - "no_throwing_strings": { - "active": 1, - "flagValue": -1 - }, - "no_trailing_semicolons": { - "active": 1, - "flagValue": -1 - }, - "no_trailing_whitespace": { - "active": 1, - "flagValue": -1 - }, - "no_unnecessary_double_quotes": { - "active": 0, - "flagValue": -1 - }, - "no_unnecessary_fat_arrows": { - "active": 1, - "flagValue": -1 - }, - "non_empty_constructor_needs_parens": { - "active": 0, - "flagValue": -1 - }, - "prefer_english_operator": { - "active": 0, - "flagValue": -1 - }, - "space_operators": { - "active": 0, - "flagValue": -1 - }, - "spacing_after_comma": { - "active": 1, - "flagValue": -1 - } - }, - "coffeeMinifyOutput": 1, - "coffeeOutputStyle": 0, - "coffeeSyntaxCheckerStyle": 1, - "externalServerAddress": "http:\/\/magicmirror.app\/v2", - "externalServerPreviewPathAddition": "", - "genericWebpageFileExtensionsString": "html, htm, shtml, shtm, xhtml, php, jsp, asp, aspx, erb, ctp", - "hamlAutoOutputPathEnabled": 1, - "hamlAutoOutputPathFilenamePattern": "*.html", - "hamlAutoOutputPathRelativePath": "", - "hamlAutoOutputPathReplace1": "", - "hamlAutoOutputPathReplace2": "", - "hamlAutoOutputPathStyle": 0, - "hamlEscapeHTMLCharacters": 0, - "hamlNoEscapeInAttributes": 0, - "hamlOutputFormat": 2, - "hamlOutputStyle": 0, - "hamlUseCDATA": 0, - "hamlUseDoubleQuotes": 0, - "hamlUseUnixNewlines": 0, - "jadeAutoOutputPathEnabled": 1, - "jadeAutoOutputPathFilenamePattern": "*.html", - "jadeAutoOutputPathRelativePath": "", - "jadeAutoOutputPathReplace1": "", - "jadeAutoOutputPathReplace2": "", - "jadeAutoOutputPathStyle": 0, - "jadeCompileDebug": 1, - "jadeOutputStyle": 0, - "javascriptAutoOutputPathEnabled": 1, - "javascriptAutoOutputPathFilenamePattern": "*-min.js", - "javascriptAutoOutputPathRelativePath": "\/min", - "javascriptAutoOutputPathReplace1": "", - "javascriptAutoOutputPathReplace2": "", - "javascriptAutoOutputPathStyle": 2, - "javascriptCreateSourceMap": 1, - "javascriptOutputStyle": 1, - "javascriptSyntaxCheckerStyle": 1, - "jsCheckerReservedNamesString": "", - "jsHintFlags2": { - "asi": { - "active": 0, - "flagValue": -1 - }, - "bitwise": { - "active": 1, - "flagValue": -1 - }, - "boss": { - "active": 0, - "flagValue": -1 - }, - "browser": { - "active": 1, - "flagValue": -1 - }, - "browserify": { - "active": 0, - "flagValue": -1 - }, - "camelcase": { - "active": 0, - "flagValue": -1 - }, - "couch": { - "active": 0, - "flagValue": -1 - }, - "curly": { - "active": 1, - "flagValue": -1 - }, - "debug": { - "active": 0, - "flagValue": -1 - }, - "devel": { - "active": 0, - "flagValue": -1 - }, - "dojo": { - "active": 0, - "flagValue": -1 - }, - "elision": { - "active": 1, - "flagValue": -1 - }, - "eqeqeq": { - "active": 1, - "flagValue": -1 - }, - "eqnull": { - "active": 0, - "flagValue": -1 - }, - "es3": { - "active": 0, - "flagValue": -1 - }, - "esnext": { - "active": 0, - "flagValue": -1 - }, - "evil": { - "active": 0, - "flagValue": -1 - }, - "expr": { - "active": 0, - "flagValue": -1 - }, - "forin": { - "active": 0, - "flagValue": -1 - }, - "freeze": { - "active": 1, - "flagValue": -1 - }, - "funcscope": { - "active": 0, - "flagValue": -1 - }, - "futurehostile": { - "active": 0, - "flagValue": -1 - }, - "globalstrict": { - "active": 0, - "flagValue": -1 - }, - "immed": { - "active": 0, - "flagValue": -1 - }, - "indent": { - "active": 0, - "flagValue": 4 - }, - "iterator": { - "active": 0, - "flagValue": -1 - }, - "jasmine": { - "active": 0, - "flagValue": -1 - }, - "jquery": { - "active": 1, - "flagValue": -1 - }, - "lastsemic": { - "active": 0, - "flagValue": -1 - }, - "latedef": { - "active": 1, - "flagValue": -1 - }, - "laxbreak": { - "active": 0, - "flagValue": -1 - }, - "laxcomma": { - "active": 0, - "flagValue": -1 - }, - "loopfunc": { - "active": 0, - "flagValue": -1 - }, - "maxcomplexity": { - "active": 0, - "flagValue": 10 - }, - "maxdepth": { - "active": 0, - "flagValue": 3 - }, - "maxlen": { - "active": 0, - "flagValue": 150 - }, - "maxparams": { - "active": 0, - "flagValue": 3 - }, - "maxstatements": { - "active": 0, - "flagValue": 4 - }, - "mocha": { - "active": 0, - "flagValue": -1 - }, - "mootools": { - "active": 0, - "flagValue": -1 - }, - "moz": { - "active": 0, - "flagValue": -1 - }, - "multistr": { - "active": 0, - "flagValue": -1 - }, - "newcap": { - "active": 1, - "flagValue": -1 - }, - "noarg": { - "active": 1, - "flagValue": -1 - }, - "nocomma": { - "active": 0, - "flagValue": -1 - }, - "node": { - "active": 0, - "flagValue": -1 - }, - "noempty": { - "active": 0, - "flagValue": -1 - }, - "nonbsp": { - "active": 0, - "flagValue": -1 - }, - "nonew": { - "active": 1, - "flagValue": -1 - }, - "nonstandard": { - "active": 0, - "flagValue": -1 - }, - "notypeof": { - "active": 1, - "flagValue": -1 - }, - "noyield": { - "active": 0, - "flagValue": -1 - }, - "onecase": { - "active": 0, - "flagValue": -1 - }, - "phantom": { - "active": 0, - "flagValue": -1 - }, - "plusplus": { - "active": 0, - "flagValue": -1 - }, - "proto": { - "active": 0, - "flagValue": -1 - }, - "prototypejs": { - "active": 0, - "flagValue": -1 - }, - "qunit": { - "active": 0, - "flagValue": -1 - }, - "regexp": { - "active": 1, - "flagValue": -1 - }, - "rhino": { - "active": 0, - "flagValue": -1 - }, - "scripturl": { - "active": 0, - "flagValue": -1 - }, - "shadow": { - "active": 0, - "flagValue": -1 - }, - "shelljs": { - "active": 0, - "flagValue": -1 - }, - "singleGroups": { - "active": 0, - "flagValue": -1 - }, - "strict": { - "active": 0, - "flagValue": -1 - }, - "sub": { - "active": 0, - "flagValue": -1 - }, - "supernew": { - "active": 0, - "flagValue": -1 - }, - "typed": { - "active": 0, - "flagValue": -1 - }, - "undef": { - "active": 1, - "flagValue": -1 - }, - "unused": { - "active": 1, - "flagValue": -1 - }, - "varstmt": { - "active": 0, - "flagValue": -1 - }, - "withstmt": { - "active": 0, - "flagValue": -1 - }, - "worker": { - "active": 0, - "flagValue": -1 - }, - "wsh": { - "active": 0, - "flagValue": -1 - }, - "yui": { - "active": 0, - "flagValue": -1 - } - }, - "jsLintFlags2": { - "bitwise": { - "active": 0, - "flagValue": -1 - }, - "browser": { - "active": 1, - "flagValue": -1 - }, - "couch": { - "active": 0, - "flagValue": -1 - }, - "devel": { - "active": 0, - "flagValue": -1 - }, - "es6": { - "active": 0, - "flagValue": -1 - }, - "eval": { - "active": 0, - "flagValue": -1 - }, - "for": { - "active": 0, - "flagValue": -1 - }, - "maxlen": { - "active": 0, - "flagValue": 150 - }, - "node": { - "active": 0, - "flagValue": -1 - }, - "this": { - "active": 0, - "flagValue": -1 - }, - "white": { - "active": 0, - "flagValue": -1 - } - }, - "jsonAutoOutputPathEnabled": 0, - "jsonAutoOutputPathFilenamePattern": "*-min.json", - "jsonAutoOutputPathRelativePath": "", - "jsonAutoOutputPathReplace1": "", - "jsonAutoOutputPathReplace2": "", - "jsonAutoOutputPathStyle": 0, - "jsonOrderOutput": 0, - "jsonOutputStyle": 1, - "kitAutoOutputPathEnabled": 1, - "kitAutoOutputPathFilenamePattern": "*.html", - "kitAutoOutputPathRelativePath": "", - "kitAutoOutputPathReplace1": "", - "kitAutoOutputPathReplace2": "", - "kitAutoOutputPathStyle": 0, - "lessAllowInsecureImports": 0, - "lessAutoOutputPathEnabled": 1, - "lessAutoOutputPathFilenamePattern": "*.css", - "lessAutoOutputPathRelativePath": "..\/css", - "lessAutoOutputPathReplace1": "less", - "lessAutoOutputPathReplace2": "css", - "lessAutoOutputPathStyle": 2, - "lessCreateSourceMap": 0, - "lessDisableJavascript": 0, - "lessIeCompatibility": 1, - "lessOutputStyle": 0, - "lessRelativeURLS": 0, - "lessStrictImports": 0, - "lessStrictMath": 0, - "lessStrictUnits": 0, - "markdownAutoOutputPathEnabled": 1, - "markdownAutoOutputPathFilenamePattern": "*.html", - "markdownAutoOutputPathRelativePath": "", - "markdownAutoOutputPathReplace1": "", - "markdownAutoOutputPathReplace2": "", - "markdownAutoOutputPathStyle": 0, - "markdownCriticStyle": 0, - "markdownEnableFootnotes": 1, - "markdownEnableLabels": 1, - "markdownEnableSmartQuotes": 1, - "markdownEscapeLineBreaks": 0, - "markdownMaskEmailAddresses": 1, - "markdownOutputFormat": 0, - "markdownOutputStyle": 0, - "markdownParseMetadata": 1, - "markdownProcessHTML": 0, - "markdownRandomFootnoteNumbers": 0, - "markdownUseCompatibilityMode": 0, - "reloadFileURLs": 0, - "sassAutoOutputPathEnabled": 1, - "sassAutoOutputPathFilenamePattern": "*.css", - "sassAutoOutputPathRelativePath": "..\/css", - "sassAutoOutputPathReplace1": "sass", - "sassAutoOutputPathReplace2": "css", - "sassAutoOutputPathStyle": 2, - "sassCreateSourceMap": 0, - "sassDebugStyle": 0, - "sassDecimalPrecision": 10, - "sassOutputStyle": 0, - "sassUseLibsass": 0, - "shouldRunAutoprefixer": 0, - "shouldRunBless": 0, - "skippedItemsString": ".svn, .git, .hg, log, _logs, _cache, cache, logs, node_modules", - "slimAutoOutputPathEnabled": 1, - "slimAutoOutputPathFilenamePattern": "*.html", - "slimAutoOutputPathRelativePath": "", - "slimAutoOutputPathReplace1": "", - "slimAutoOutputPathReplace2": "", - "slimAutoOutputPathStyle": 0, - "slimCompileOnly": 0, - "slimLogicless": 0, - "slimOutputFormat": 0, - "slimOutputStyle": 1, - "slimRailsCompatible": 0, - "stylusAutoOutputPathEnabled": 1, - "stylusAutoOutputPathFilenamePattern": "*.css", - "stylusAutoOutputPathRelativePath": "..\/css", - "stylusAutoOutputPathReplace1": "stylus", - "stylusAutoOutputPathReplace2": "css", - "stylusAutoOutputPathStyle": 2, - "stylusCreateSourceMap": 0, - "stylusDebugStyle": 0, - "stylusImportCSS": 0, - "stylusOutputStyle": 0, - "stylusResolveRelativeURLS": 0, - "typescriptAutoOutputPathEnabled": 1, - "typescriptAutoOutputPathFilenamePattern": "*.js", - "typescriptAutoOutputPathRelativePath": "\/js", - "typescriptAutoOutputPathReplace1": "", - "typescriptAutoOutputPathReplace2": "", - "typescriptAutoOutputPathStyle": 2, - "typescriptCreateDeclarationFile": 0, - "typescriptCreateSourceMap": 0, - "typescriptJSXMode": 0, - "typescriptMinifyOutput": 0, - "typescriptModuleResolutionType": 0, - "typescriptModuleType": 0, - "typescriptNoImplicitAny": 0, - "typescriptPreserveConstEnums": 0, - "typescriptRemoveComments": 0, - "typescriptSuppressImplicitAnyIndexErrors": 0, - "typescriptTargetECMAVersion": 0, - "uglifyDefinesString": "", - "uglifyFlags2": { - "ascii-only": { - "active": 0, - "flagValue": -1 - }, - "bare-returns": { - "active": 0, - "flagValue": -1 - }, - "booleans": { - "active": 1, - "flagValue": -1 - }, - "bracketize": { - "active": 0, - "flagValue": -1 - }, - "cascade": { - "active": 1, - "flagValue": -1 - }, - "comments": { - "active": 1, - "flagValue": -1 - }, - "comparisons": { - "active": 1, - "flagValue": -1 - }, - "compress": { - "active": 1, - "flagValue": -1 - }, - "conditionals": { - "active": 1, - "flagValue": -1 - }, - "dead_code": { - "active": 0, - "flagValue": -1 - }, - "drop_console": { - "active": 0, - "flagValue": -1 - }, - "drop_debugger": { - "active": 1, - "flagValue": -1 - }, - "eval": { - "active": 0, - "flagValue": -1 - }, - "evaluate": { - "active": 1, - "flagValue": -1 - }, - "hoist_funs": { - "active": 1, - "flagValue": -1 - }, - "hoist_vars": { - "active": 0, - "flagValue": -1 - }, - "if_return": { - "active": 1, - "flagValue": -1 - }, - "indent-level": { - "active": 0, - "flagValue": 4 - }, - "indent-start": { - "active": 0, - "flagValue": 0 - }, - "inline-script": { - "active": 0, - "flagValue": -1 - }, - "join_vars": { - "active": 1, - "flagValue": -1 - }, - "keep_fargs": { - "active": 0, - "flagValue": -1 - }, - "keep_fnames": { - "active": 0, - "flagValue": -1 - }, - "loops": { - "active": 1, - "flagValue": -1 - }, - "mangle": { - "active": 1, - "flagValue": -1 - }, - "max-line-len": { - "active": 1, - "flagValue": 32000 - }, - "negate_iife": { - "active": 1, - "flagValue": -1 - }, - "properties": { - "active": 1, - "flagValue": -1 - }, - "pure_getters": { - "active": 0, - "flagValue": -1 - }, - "quote-keys": { - "active": 0, - "flagValue": -1 - }, - "screw-ie8": { - "active": 0, - "flagValue": -1 - }, - "semicolons": { - "active": 1, - "flagValue": -1 - }, - "sequences": { - "active": 1, - "flagValue": -1 - }, - "sort": { - "active": 0, - "flagValue": -1 - }, - "space-colon": { - "active": 1, - "flagValue": -1 - }, - "toplevel": { - "active": 0, - "flagValue": -1 - }, - "unsafe": { - "active": 0, - "flagValue": -1 - }, - "unused": { - "active": 0, - "flagValue": -1 - }, - "warnings": { - "active": 0, - "flagValue": -1 - }, - "width": { - "active": 1, - "flagValue": 80 - } - }, - "uglifyReservedNamesString": "$", - "websiteRelativeRoot": "" - }, -"settingsFileVersion": "2" -} \ No newline at end of file diff --git a/config/config.js b/config/config.js.sample similarity index 53% rename from config/config.js rename to config/config.js.sample index 58b8dc8d..25565b70 100644 --- a/config/config.js +++ b/config/config.js.sample @@ -9,6 +9,7 @@ var config = { language: 'en', + timeFormat: 24, modules: [ { @@ -20,8 +21,21 @@ var config = { position: 'lower_third', }, { - module: 'helloworld', - position: 'top_right' + module: 'currentweather', + position: 'top_right', + config: { + location: 'New York', + appid: 'YOUR_OPENWEATHER_API_KEY' + } + }, + { + module: 'weatherforecast', + position: 'top_right', + header: 'Weather Forecast', + config: { + location: 'New York', + appid: 'YOUR_OPENWEATHER_API_KEY' + } }, { module: 'helloworld', diff --git a/css/main.css b/css/main.css index 9293685d..de6b2266 100644 --- a/css/main.css +++ b/css/main.css @@ -20,18 +20,21 @@ body { .xsmall {font-size: 15px; line-height: 20px;} .small {font-size: 20px; line-height: 25px;} .medium {font-size: 30px; line-height: 35px;} -.large {font-size: 60px; line-height: 60px;} -.xlarge {font-size: 70px; line-height: 70px; letter-spacing: -3px;} +.large {font-size: 65px; line-height: 65px;} +.xlarge {font-size: 75px; line-height: 75px; letter-spacing: -3px;} .thin {font-family: 'robotothin'; } .light {font-family: 'roboto_condensedlight'; } .regular {font-family: 'roboto_condensedregular';} .bold {font-family: 'roboto_condensedbold';} +.align-right {text-align: right;} + + header { - margin-top: 50px; + margin-top: 40px; text-transform: uppercase; - font-size: 0.4em; + font-size: 15px; font-family: 'roboto_condensedregular'; border-bottom: 1px solid #333; line-height: 0.35em; @@ -40,6 +43,10 @@ header { color: #666; } +header:first-child { + margin-top: 0px; +} + sup { font-size: 50%; line-height: 50%; @@ -113,4 +120,7 @@ sup { } .region.right { text-align: right; +} +.region.right table { + float: right; } \ No newline at end of file diff --git a/js/defaults.js b/js/defaults.js index f7ec13d0..97ac99f0 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,6 +10,7 @@ var defaults = { language: 'en', + timeFormat: 24, modules: [ { diff --git a/js/loader.js b/js/loader.js index 3fba0b33..45129589 100644 --- a/js/loader.js +++ b/js/loader.js @@ -80,6 +80,7 @@ var Loader = (function() { path: config.paths.modules + '/' + module, file: module + '.js', position: moduleData.position, + header: moduleData.header, config: moduleData.config }); diff --git a/js/main.js b/js/main.js index d2a88558..2325f9e0 100644 --- a/js/main.js +++ b/js/main.js @@ -22,10 +22,18 @@ var MM = (function() { for (var m in modules) { var module = modules[m]; if (module.data.position) { - var dom = document.createElement("div"); - dom.id = module.identifier; var wrapper = selectWrapper(module.data.position); + + if (typeof module.data.header !== 'undefined' && module.data.header !== '') { + var header = document.createElement("header"); + header.innerHTML = module.data.header; + wrapper.appendChild(header); + } + + var dom = document.createElement("div"); + dom.id = module.identifier; + dom.className = module.name; wrapper.appendChild(dom); dom.appendChild(module.getDom()); @@ -75,10 +83,19 @@ var MM = (function() { */ var updateDom = function(module, speed) { var wrapper = document.getElementById(module.identifier); + var newContent = module.getDom(); + + var tempWrapper = document.createElement('div'); + tempWrapper.appendChild(newContent); + + if (tempWrapper.innerHTML === wrapper.innerHTML) { + // Content did not change. Abort update. + return; + } if (!speed) { wrapper.innerHTML = null; - wrapper.appendChild(module.getDom()); + wrapper.appendChild(newContent); return; } @@ -88,7 +105,7 @@ var MM = (function() { setTimeout(function() { wrapper.innerHTML = null; - wrapper.appendChild(module.getDom()); + wrapper.appendChild(newContent); wrapper.style.opacity = 1; }, speed / 2); diff --git a/modules/clock/clock.js b/modules/clock/clock.js index 659f7ecc..f4ea72b6 100644 --- a/modules/clock/clock.js +++ b/modules/clock/clock.js @@ -11,7 +11,7 @@ Module.create({ // Module config defaults. defaults: { - timeFormat: 24, + timeFormat: config.timeFormat, displaySeconds: true, }, diff --git a/modules/currentweather/currentweather.css b/modules/currentweather/currentweather.css new file mode 100644 index 00000000..b953534b --- /dev/null +++ b/modules/currentweather/currentweather.css @@ -0,0 +1,9 @@ +.currentweather .weathericon { + font-size: 75%; + line-height: 65px; + display: inline-block; + + -ms-transform: translate(0px,-3px); /* IE 9 */ + -webkit-transform: translate(0px,-3px); /* Safari */ + transform: translate(0px,-3px); +} \ No newline at end of file diff --git a/modules/currentweather/currentweather.js b/modules/currentweather/currentweather.js new file mode 100644 index 00000000..1219a8d1 --- /dev/null +++ b/modules/currentweather/currentweather.js @@ -0,0 +1,271 @@ +/* global Module */ + +/* Magic Mirror + * Module: CurrentWeather + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +Module.create({ + + // Default module config. + defaults: { + location: '', + appid: '', + units: 'metric', + updateInterval: 10 * 60 * 1000, // every 10 minutes + animationSpeed: 1000, + timeFormat: config.timeFormat, + lang: config.language, + + initialLoadDelay: 0, // 0 seconds delay + retryDelay: 2500, + + apiVersion: '2.5', + apiBase: 'http://api.openweathermap.org/data/', + weatherEndpoint: 'weather', + + iconTable: { + '01d':'wi-day-sunny', + '02d':'wi-day-cloudy', + '03d':'wi-cloudy', + '04d':'wi-cloudy-windy', + '09d':'wi-showers', + '10d':'wi-rain', + '11d':'wi-thunderstorm', + '13d':'wi-snow', + '50d':'wi-fog', + '01n':'wi-night-clear', + '02n':'wi-night-cloudy', + '03n':'wi-night-cloudy', + '04n':'wi-night-cloudy', + '09n':'wi-night-showers', + '10n':'wi-night-rain', + '11n':'wi-night-thunderstorm', + '13n':'wi-night-snow', + '50n':'wi-night-alt-cloudy-windy' + }, + }, + + // Define required scripts. + getScripts: function() { + return ['moment.js']; + }, + + // Define required scripts. + getStyles: function() { + return ['weather-icons.css', 'currentweather.css']; + }, + + + // Define start sequence. + start: function() { + Log.info('Starting module: ' + this.name); + + // Set locale. + moment.locale(config.language); + + this.windSpeed = null; + this.sunriseSunsetTime = null; + this.sunriseSunsetIcon = null; + this.temperature = null; + this.weatherType = null; + + this.loaded = false; + this.scheduleUpdate(this.config.initialLoadDelay); + + this.updateTimer = null; + + }, + + // Override dom generator. + getDom: function() { + var wrapper = document.createElement("div"); + + if (this.config.appid === '') { + wrapper.innerHTML = "Please set the correct openweather appid in the config for module: " + this.name + "."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (this.config.location === '') { + wrapper.innerHTML = "Please set the openweather location in the config for module: " + this.name + "."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (!this.loaded) { + wrapper.innerHTML = "Loading weather ..."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + + var small = document.createElement("div"); + small.className = "normal medium"; + + var windIcon = document.createElement("span"); + windIcon.className = "wi wi-strong-wind dimmed"; + small.appendChild(windIcon); + + var windSpeed = document.createElement("span"); + windSpeed.innerHTML = " " + this.windSpeed; + small.appendChild(windSpeed); + + var spacer = document.createElement("span"); + spacer.innerHTML = " "; + small.appendChild(spacer); + + var sunriseSunsetIcon = document.createElement("span"); + sunriseSunsetIcon.className = "wi dimmed " + this.sunriseSunsetIcon; + small.appendChild(sunriseSunsetIcon); + + var sunriseSunsetTime = document.createElement("span"); + sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime; + small.appendChild(sunriseSunsetTime); + + var large = document.createElement("div"); + large.className = "large light"; + + var weatherIcon = document.createElement("span"); + weatherIcon.className = "wi weathericon " + this.weatherType; + large.appendChild(weatherIcon); + + var temperature = document.createElement("span"); + temperature.className = "bright"; + temperature.innerHTML = " " + this.temperature + '°'; + large.appendChild(temperature); + + wrapper.appendChild(small); + wrapper.appendChild(large); + return wrapper; + }, + + + /* updateWeather(compliments) + * Requests new data from openweather.org. + * Calls processWeather on succesfull response. + */ + updateWeather: function() { + var url = this.config.apiBase + this.config.apiVersion + '/' + this.config.weatherEndpoint + this.getParams(); + var self = this; + var retry = true; + + var weatherRequest = new XMLHttpRequest(); + weatherRequest.open("GET", url, true); + weatherRequest.onreadystatechange = function() { + if(this.readyState === 4) { + if(this.status === 200) { + self.processWeather(JSON.parse(this.response)); + } else if (this.status === 401) { + self.config.appid = ''; + self.updateDom(self.config.animationSpeed); + + Log.error(self.name + ": Incorrect APPID."); + retry = false; + } else { + Log.error(self.name + ": Could not load weather."); + } + + if (retry) { + self.scheduleUpdate((self.loaded) ? -1 : self.config.retryDelay); + } + } + }; + weatherRequest.send(); + }, + + /* getParams(compliments) + * Generates an url with api parameters based on the config. + * + * return String - URL params. + */ + getParams: function() { + var params = "?"; + params += 'q=' + this.config.location; + params += '&units=' + this.config.units; + params += '&lang=' + this.config.lang; + params += '&APPID=' + this.config.appid; + + return params; + }, + + /* processWeather(data) + * Uses the received data to set the various values. + * + * argument data object - Weather information received form openweather.org. + */ + processWeather: function(data) { + this.temperature = this.roundValue(data.main.temp); + this.windSpeed = this.ms2Beaufort(this.roundValue(data.wind.speed)); + this.weatherType = this.config.iconTable[data.weather[0].icon]; + + + + var now = moment().format('x'); + var sunrise = moment(data.sys.sunrise*1000).format('x'); + var sunset = moment(data.sys.sunset*1000).format('x'); + + + if (sunrise < now && sunset > now) { + this.sunriseSunsetTime = moment(data.sys.sunset*1000).format((this.config.timeFormat === 24) ? 'HH:mm' : 'hh:mm a'); + this.sunriseSunsetIcon = 'wi-sunset'; + } else { + this.sunriseSunsetTime = moment(data.sys.sunrise*1000).format((this.config.timeFormat === 24) ? 'HH:mm' : 'hh:mm a'); + this.sunriseSunsetIcon = 'wi-sunrise'; + + } + + this.loaded = true; + this.updateDom(this.config.animationSpeed); + }, + + /* scheduleUpdate() + * Schedule next update. + * + * argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used. + */ + scheduleUpdate: function(delay) { + var nextLoad = this.config.updateInterval; + if (typeof delay !== 'undefined' && delay >= 0) { + nextLoad = delay; + } + + var self = this; + setTimeout(function() { + self.updateWeather(); + }, nextLoad); + }, + + /* ms2Beaufort(ms) + * Converts m2 to beaufort (windspeed). + * + * argument ms number - Windspeed in m/s. + * + * return number - Windspeed in beaufort. + */ + ms2Beaufort: function(ms) { + var kmh = ms * 60 * 60 / 1000; + var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; + for (var beaufort in speeds) { + var speed = speeds[beaufort]; + if (speed > kmh) { + return beaufort; + } + } + return 12; + }, + + /* function(temperature) + * Rounds a temperature to 1 decimal. + * + * argument temperature number - Temperature. + * + * return number - Rounded Temperature. + */ + roundValue: function (temperature) { + return parseFloat(temperature).toFixed(1); + } +}); + diff --git a/modules/helper_test/node_helper.js b/modules/helper_test/node_helper.js deleted file mode 100644 index ea00fc25..00000000 --- a/modules/helper_test/node_helper.js +++ /dev/null @@ -1,2 +0,0 @@ -'use strict'; -console.log("test"); \ No newline at end of file diff --git a/modules/weatherforecast/weatherforecast.css b/modules/weatherforecast/weatherforecast.css new file mode 100644 index 00000000..323e65a6 --- /dev/null +++ b/modules/weatherforecast/weatherforecast.css @@ -0,0 +1,18 @@ +.weatherforecast .day { + padding-left: 0px; + padding-right: 20px; +} + +.weatherforecast .weather-icon { + padding-right: 30px; +} + +.weatherforecast .min-temp { + padding-left: 10px; + padding-right: 0px; +} + +.weatherforecast table { + border-spacing: 0px; + border-collapse: separate; +} diff --git a/modules/weatherforecast/weatherforecast.js b/modules/weatherforecast/weatherforecast.js new file mode 100644 index 00000000..a6ff08ef --- /dev/null +++ b/modules/weatherforecast/weatherforecast.js @@ -0,0 +1,263 @@ +/* global Module */ + +/* Magic Mirror + * Module: WeatherForecast + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +Module.create({ + + // Default module config. + defaults: { + location: '', + appid: '', + units: 'metric', + updateInterval: 10 * 60 * 1000, // every 10 minutes + animationSpeed: 1000, + timeFormat: config.timeFormat, + lang: config.language, + + initialLoadDelay: 5000, // 5 seconds delay. This delay is used to keep the OpenWeather API happy. + retryDelay: 2500, + + apiVersion: '2.5', + apiBase: 'http://api.openweathermap.org/data/', + forecastEndpoint: 'forecast/daily', + + iconTable: { + '01d':'wi-day-sunny', + '02d':'wi-day-cloudy', + '03d':'wi-cloudy', + '04d':'wi-cloudy-windy', + '09d':'wi-showers', + '10d':'wi-rain', + '11d':'wi-thunderstorm', + '13d':'wi-snow', + '50d':'wi-fog', + '01n':'wi-night-clear', + '02n':'wi-night-cloudy', + '03n':'wi-night-cloudy', + '04n':'wi-night-cloudy', + '09n':'wi-night-showers', + '10n':'wi-night-rain', + '11n':'wi-night-thunderstorm', + '13n':'wi-night-snow', + '50n':'wi-night-alt-cloudy-windy' + }, + }, + + // Define required scripts. + getScripts: function() { + return ['moment.js']; + }, + + // Define required scripts. + getStyles: function() { + return ['weather-icons.css', 'weatherforecast.css']; + }, + + + // Define start sequence. + start: function() { + Log.info('Starting module: ' + this.name); + + // Set locale. + moment.locale(config.language); + + this.forecast = []; + this.loaded = false; + this.scheduleUpdate(this.config.initialLoadDelay); + + this.updateTimer = null; + + }, + + // Override dom generator. + getDom: function() { + var wrapper = document.createElement("div"); + + if (this.config.appid === '') { + wrapper.innerHTML = "Please set the correct openweather appid in the config for module: " + this.name + "."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (this.config.location === '') { + wrapper.innerHTML = "Please set the openweather location in the config for module: " + this.name + "."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (!this.loaded) { + wrapper.innerHTML = "Loading weather ..."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + + var table = document.createElement("table"); + table.className = "small"; + + for (var f in this.forecast) { + var forecast = this.forecast[f]; + + var row = document.createElement("tr"); + table.appendChild(row); + + var dayCell = document.createElement("td"); + dayCell.className = 'day'; + dayCell.innerHTML = forecast.day; + row.appendChild(dayCell); + + var iconCell = document.createElement("td"); + iconCell.className = "bright weather-icon"; + row.appendChild(iconCell); + + var icon = document.createElement("span"); + icon.className = forecast.icon; + iconCell.appendChild(icon); + + var maxTempCell = document.createElement("td"); + maxTempCell.innerHTML = forecast.maxTemp; + maxTempCell.className = 'align-right bright max-temp'; + row.appendChild(maxTempCell); + + var minTempCell = document.createElement("td"); + minTempCell.innerHTML = forecast.minTemp; + minTempCell.className = 'align-right min-temp'; + row.appendChild(minTempCell); + + } + + + + return table; + }, + + + /* updateWeather(compliments) + * Requests new data from openweather.org. + * Calls processWeather on succesfull response. + */ + updateWeather: function() { + var url = this.config.apiBase + this.config.apiVersion + '/' + this.config.forecastEndpoint + this.getParams(); + var self = this; + var retry = true; + + var weatherRequest = new XMLHttpRequest(); + weatherRequest.open("GET", url, true); + weatherRequest.onreadystatechange = function() { + if(this.readyState === 4) { + if(this.status === 200) { + self.processWeather(JSON.parse(this.response)); + } else if (this.status === 401) { + self.config.appid = ''; + self.updateDom(self.config.animationSpeed); + + Log.error(self.name + ": Incorrect APPID."); + retry = false; + } else { + Log.error(self.name + ": Could not load weather."); + } + + if (retry) { + self.scheduleUpdate((self.loaded) ? -1 : self.config.retryDelay); + } + } + }; + weatherRequest.send(); + }, + + /* getParams(compliments) + * Generates an url with api parameters based on the config. + * + * return String - URL params. + */ + getParams: function() { + var params = "?"; + params += 'q=' + this.config.location; + params += '&units=' + this.config.units; + params += '&lang=' + this.config.lang; + params += '&APPID=' + this.config.appid; + + return params; + }, + + /* processWeather(data) + * Uses the received data to set the various values. + * + * argument data object - Weather information received form openweather.org. + */ + processWeather: function(data) { + + this.forecast = []; + for (var i = 0, count = data.list.length; i < count; i++) { + + var forecast = data.list[i]; + this.forecast.push({ + + day: moment(forecast.dt, 'X').format('ddd.'), + icon: this.config.iconTable[forecast.weather[0].icon], + maxTemp: this.roundValue(forecast.temp.max), + minTemp: this.roundValue(forecast.temp.min) + + }); + } + + //Log.log(this.forecast); + + this.loaded = true; + this.updateDom(this.config.animationSpeed); + }, + + /* scheduleUpdate() + * Schedule next update. + * + * argument delay number - Milliseconds before next update. If empty, this.config.updateInterval is used. + */ + scheduleUpdate: function(delay) { + var nextLoad = this.config.updateInterval; + if (typeof delay !== 'undefined' && delay >= 0) { + nextLoad = delay; + } + + var self = this; + clearTimeout(this.updateTimer); + this.updateTimer = setTimeout(function() { + self.updateWeather(); + }, nextLoad); + }, + + /* ms2Beaufort(ms) + * Converts m2 to beaufort (windspeed). + * + * argument ms number - Windspeed in m/s. + * + * return number - Windspeed in beaufort. + */ + ms2Beaufort: function(ms) { + var kmh = ms * 60 * 60 / 1000; + var speeds = [1, 5, 11, 19, 28, 38, 49, 61, 74, 88, 102, 117, 1000]; + for (var beaufort in speeds) { + var speed = speeds[beaufort]; + if (speed > kmh) { + return beaufort; + } + } + return 12; + }, + + /* function(temperature) + * Rounds a temperature to 1 decimal. + * + * argument temperature number - Temperature. + * + * return number - Rounded Temperature. + */ + roundValue: function (temperature) { + return parseFloat(temperature).toFixed(1); + } +}); + diff --git a/vendor/vendor.js b/vendor/vendor.js index a6e60420..3d984d03 100644 --- a/vendor/vendor.js +++ b/vendor/vendor.js @@ -9,4 +9,5 @@ var vendor = { 'moment.js' : 'moment/moment-with-locales.min.js', + 'weather-icons.css': 'weather-icons/weather-icons.css' }; \ No newline at end of file diff --git a/vendor/weather-icons/weather-icons.css b/vendor/weather-icons/weather-icons.css new file mode 100755 index 00000000..c547ce67 --- /dev/null +++ b/vendor/weather-icons/weather-icons.css @@ -0,0 +1,327 @@ +/*! + * Weather Icons Beta 1 + * Weather themed icons for Bootstrap + * ------------------------------------------------------------------------------ + * Maintained at http://erikflowers.github.io/weather-icons + * http://twitter.com/Erik_UX + * + * License + * ------------------------------------------------------------------------------ + * - Fpmt licensed under SIL OFL 1.1 - + * http://scripts.sil.org/OFL + * - CSS and LESS are licensed under MIT License - + * http://opensource.org/licenses/mit-license.html + * - Documentation licensed under CC BY 3.0 - + * http://creativecommons.org/licenses/by/3.0/ + * - Inspired by and works great as a companion with Font Aweosme + * "Font Awesome by Dave Gandy - http://fontawesome.io" + * + * Weather Icons Bootstrap Package Author - Erik Flowers - erik@helloerik.com + * Weather Icons gives full credit for inspiration to Font Awesome and makes no + * claim to invention, intellectual property, or ownership of methodology. + * + * Support Open Source! + * + * ------------------------------------------------------------------------------ + * Email: erik@helloerik.com + * Twitter: http://twitter.com/Erik_UX + */ +@font-face { + font-family: 'weather'; + src: url('weathericons-regular-webfont.eot'); + src: url('weathericons-regular-webfont.eot?#iefix') format('embedded-opentype'), url('weathericons-regular-webfont.woff') format('woff'), url('weathericons-regular-webfont.ttf') format('truetype'), url('weathericons-regular-webfont.svg#weathericons-regular-webfontRg') format('svg'); + font-weight: normal; + font-style: normal; +} +[class^="wi-"], +[class*=" wi-"] { + font-family: weather; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + text-transform: none; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; +} +[class^="wi-"]:before, +[class*=" wi-"]:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} +.wi-day-cloudy-gusts:before { + content: "\f000"; +} +.wi-day-cloudy-windy:before { + content: "\f001"; +} +.wi-day-cloudy:before { + content: "\f002"; +} +.wi-day-fog:before { + content: "\f003"; +} +.wi-day-hail:before { + content: "\f004"; +} +.wi-day-lightning:before { + content: "\f005"; +} +.wi-day-rain-mix:before { + content: "\f006"; +} +.wi-day-rain-wind:before { + content: "\f007"; +} +.wi-day-rain:before { + content: "\f008"; +} +.wi-day-showers:before { + content: "\f009"; +} +.wi-day-snow:before { + content: "\f00a"; +} +.wi-day-sprinkle:before { + content: "\f00b"; +} +.wi-day-sunny-overcast:before { + content: "\f00c"; +} +.wi-day-sunny:before { + content: "\f00d"; +} +.wi-day-storm-showers:before { + content: "\f00e"; +} +.wi-day-thunderstorm:before { + content: "\f010"; +} +.wi-cloudy-gusts:before { + content: "\f011"; +} +.wi-cloudy-windy:before { + content: "\f012"; +} +.wi-cloudy:before { + content: "\f013"; +} +.wi-fog:before { + content: "\f014"; +} +.wi-hail:before { + content: "\f015"; +} +.wi-lightning:before { + content: "\f016"; +} +.wi-rain-mix:before { + content: "\f017"; +} +.wi-rain-wind:before { + content: "\f018"; +} +.wi-rain:before { + content: "\f019"; +} +.wi-showers:before { + content: "\f01a"; +} +.wi-snow:before { + content: "\f01b"; +} +.wi-sprinkle:before { + content: "\f01c"; +} +.wi-storm-showers:before { + content: "\f01d"; +} +.wi-thunderstorm:before { + content: "\f01e"; +} +.wi-windy:before { + content: "\f021"; +} +.wi-night-alt-cloudy-gusts:before { + content: "\f022"; +} +.wi-night-alt-cloudy-windy:before { + content: "\f023"; +} +.wi-night-alt-hail:before { + content: "\f024"; +} +.wi-night-alt-lightning:before { + content: "\f025"; +} +.wi-night-alt-rain-mix:before { + content: "\f026"; +} +.wi-night-alt-rain-wind:before { + content: "\f027"; +} +.wi-night-alt-rain:before { + content: "\f028"; +} +.wi-night-alt-showers:before { + content: "\f029"; +} +.wi-night-alt-snow:before { + content: "\f02a"; +} +.wi-night-alt-sprinkle:before { + content: "\f02b"; +} +.wi-night-alt-storm-showers:before { + content: "\f02c"; +} +.wi-night-alt-thunderstorm:before { + content: "\f02d"; +} +.wi-night-clear:before { + content: "\f02e"; +} +.wi-night-cloudy-gusts:before { + content: "\f02f"; +} +.wi-night-cloudy-windy:before { + content: "\f030"; +} +.wi-night-cloudy:before { + content: "\f031"; +} +.wi-night-hail:before { + content: "\f032"; +} +.wi-night-lightning:before { + content: "\f033"; +} +.wi-night-rain-mix:before { + content: "\f034"; +} +.wi-night-rain-wind:before { + content: "\f035"; +} +.wi-night-rain:before { + content: "\f036"; +} +.wi-night-showers:before { + content: "\f037"; +} +.wi-night-snow:before { + content: "\f038"; +} +.wi-night-sprinkle:before { + content: "\f039"; +} +.wi-night-storm-showers:before { + content: "\f03a"; +} +.wi-night-thunderstorm:before { + content: "\f03b"; +} +.wi-celcius:before { + content: "\f03c"; +} +.wi-cloud-down:before { + content: "\f03d"; +} +.wi-cloud-refresh:before { + content: "\f03e"; +} +.wi-cloud-up:before { + content: "\f040"; +} +.wi-cloud:before { + content: "\f041"; +} +.wi-degrees:before { + content: "\f042"; +} +.wi-down-left:before { + content: "\f043"; +} +.wi-down:before { + content: "\f044"; +} +.wi-fahrenheit:before { + content: "\f045"; +} +.wi-horizon-alt:before { + content: "\f046"; +} +.wi-horizon:before { + content: "\f047"; +} +.wi-left:before { + content: "\f048"; +} +.wi-lightning:before { + content: "\f016"; +} +.wi-night-fog:before { + content: "\f04a"; +} +.wi-refresh-alt:before { + content: "\f04b"; +} +.wi-refresh:before { + content: "\f04c"; +} +.wi-right:before { + content: "\f04d"; +} +.wi-sprinkles:before { + content: "\f04e"; +} +.wi-strong-wind:before { + content: "\f050"; +} +.wi-sunrise:before { + content: "\f051"; +} +.wi-sunset:before { + content: "\f052"; +} +.wi-thermometer-exterior:before { + content: "\f053"; +} +.wi-thermometer-internal:before { + content: "\f054"; +} +.wi-thermometer:before { + content: "\f055"; +} +.wi-tornado:before { + content: "\f056"; +} +.wi-up-right:before { + content: "\f057"; +} +.wi-up:before { + content: "\f058"; +} +.wi-wind-east:before { + content: "\f059"; +} +.wi-wind-north-east:before { + content: "\f05a"; +} +.wi-wind-north-west:before { + content: "\f05b"; +} +.wi-wind-north:before { + content: "\f05c"; +} +.wi-wind-south-east:before { + content: "\f05d"; +} +.wi-wind-south-west:before { + content: "\f05e"; +} +.wi-wind-south:before { + content: "\f060"; +} +.wi-wind-west:before { + content: "\f061"; +} diff --git a/vendor/weather-icons/weathericons-regular-webfont.eot b/vendor/weather-icons/weathericons-regular-webfont.eot new file mode 100755 index 0000000000000000000000000000000000000000..d9f8a717f7115e9837247e69fc47819f94b27f07 GIT binary patch literal 28904 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

n2}_6E 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 gdpAu0GKi(!bFS%#L7==!prEVrOWLzYoJBDu-~i + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/weather-icons/weathericons-regular-webfont.ttf b/vendor/weather-icons/weathericons-regular-webfont.ttf new file mode 100755 index 0000000000000000000000000000000000000000..e10fbc832b3884a2b34884b14fc433be8ac87697 GIT binary patch literal 50368 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 YSskzjD_mGvuoNo*0003|>i+fs0CpzrHUIzs literal 0 HcmV?d00001 From 872d8584fb73bc694473c34d72b8c3fe6ca38ab1 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 13:28:51 +0200 Subject: [PATCH 2/8] Git ignore changes. --- .gitignore | 1 + config/.gitignore | 1 + 2 files changed, 2 insertions(+) create mode 100644 .gitignore create mode 100644 config/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 00000000..a2d72a24 --- /dev/null +++ b/config/.gitignore @@ -0,0 +1 @@ +config.js \ No newline at end of file From 90c62837426c4f5035d79715ae6881d2eeef7acf Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 13:35:55 +0200 Subject: [PATCH 3/8] Add configuration instructions and todo. --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 33bc3757..498717ec 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,23 @@ # MagicMirror V2 This version of the Magic Mirror software focusses on a modular plugin system. Besides that, the Magic Mirror software now also uses [Electron](http://electron.atom.io/), so no more webserver or browser installs necessary. +#WARNING: THIS VERSION IS IN A VERY EARLY STAGE. IT IS NOT COMPLETED YET. PLEASE USE THE MASTER BRANCH. + ##Usage 1. Install [Node.js](https://nodejs.org/en/) 2. Execute `npm install && npm start`. +##Configuration +1. Duplicate `config/config.js.sample` to `config/config.js`. +2. Modify your required settings. + ##Todo Things that still have to be implemented or changed. -###Helper scripts +####Loader +- Loading of module uses `eval()`. We might want to look into a better solution. [loader.js#L112](https://github.com/MichMich/MagicMirror/blob/v2-beta/js/loader.js#L112). + +####Helper scripts - Only start helper scripts of modules that are actually loaded in the UI (config.js) - Notification system, so that not every helper scripts needs it's own socket to the UI. -#WARNING: THIS VERSION IS IN A VERY EARLY STAGE. IT IS NOT COMPLETED YET. PLEASE USE THE MASTER BRANCH. + From 4fb7f099dec85aec1b4ac76a29a7c7f207c9fe76 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 15:39:54 +0200 Subject: [PATCH 4/8] Output node_helper output to console. --- js/electron.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/js/electron.js b/js/electron.js index 224c6554..cd2a4179 100755 --- a/js/electron.js +++ b/js/electron.js @@ -40,11 +40,29 @@ var module_loader = walk.walk(__dirname + '/../modules', { followLinks: false } module_loader.on('file', function(root, stat, next) { //if file is called node_helper.js load it if (stat.name == "node_helper.js"){ + var module = (root + '/' + stat.name).split("/"); + var moduleName = module[module.length-2]; + //start module as child - spawn('node', [root + '/' + stat.name]) + var child = spawn('node', [root + '/' + stat.name]) + + // Make sure the output is logged. + child.stdout.on('data', function(data) { + process.stdout.write(moduleName + ': ' + data); + }); + + child.stderr.on('data', function(data) { + process.stdout.write(moduleName + ': ' + data); + }); + + child.on('close', function(code) { + console.log(moduleName + ' closing code: ' + code); + }); + + //Log module name - var module = (root + '/' + stat.name).split("/") - console.log("Started helper script for module " + module[module.length-2] + "."); + + console.log("Started helper script for module " + moduleName + "."); } next(); }); From c09f8e97f7a7628160b67839af428180a3f6b9d9 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 15:44:43 +0200 Subject: [PATCH 5/8] Add news feed module. --- README.md | 1 + config/config.js.sample | 5 +- modules/newsfeed/newsfeed.js | 150 ++++++++++++++++++++++++++++++++ modules/newsfeed/node_helper.js | 74 ++++++++++++++++ package.json | 64 +++++++------- 5 files changed, 262 insertions(+), 32 deletions(-) create mode 100644 modules/newsfeed/newsfeed.js create mode 100644 modules/newsfeed/node_helper.js diff --git a/README.md b/README.md index 498717ec..7d70cb88 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,6 @@ Things that still have to be implemented or changed. ####Helper scripts - Only start helper scripts of modules that are actually loaded in the UI (config.js) - Notification system, so that not every helper scripts needs it's own socket to the UI. +- `modules/newsfeed/node_helper.js` now spawns it's own epxress webserver on port 8080. We need to create a solution for every module that needs a server side url. diff --git a/config/config.js.sample b/config/config.js.sample index 25565b70..9e301459 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -38,10 +38,11 @@ var config = { } }, { - module: 'helloworld', + module: 'newsfeed', position: 'bottom_bar', config: { - text: 'Magic Mirror V2' + feedUrl: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml', + showPublishDate: true, } }, ] diff --git a/modules/newsfeed/newsfeed.js b/modules/newsfeed/newsfeed.js new file mode 100644 index 00000000..f4bbccd7 --- /dev/null +++ b/modules/newsfeed/newsfeed.js @@ -0,0 +1,150 @@ +/* global Module */ + +/* Magic Mirror + * Module: NewsFeed + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +Module.create({ + + // Default module config. + defaults: { + feedUrl: 'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml', + showPublishDate: true, + reloadInterval: 10 * 60 * 1000, // every 10 minutes + updateInterval: 7.5 * 1000, + animationSpeed: 2.5 * 1000, + + + proxyUrl: 'http://localhost:8080/?url=', + initialLoadDelay: 0, // 5 seconds delay. This delay is used to keep the OpenWeather API happy. + retryDelay: 2500, + }, + + // Define required scripts. + getScripts: function() { + return ['moment.js']; + }, + + // Define start sequence. + start: function() { + Log.info('Starting module: ' + this.name); + + // Set locale. + moment.locale(config.language); + + this.newsItems = []; + this.loaded = false; + this.scheduleFetch(this.config.initialLoadDelay); + + this.fetchTimer = null; + this.activeItem = 0; + }, + + // Override dom generator. + getDom: function() { + var wrapper = document.createElement("div"); + + if (this.activeItem >= this.newsItems.length) { + this.activeItem = 0; + } + + if (this.newsItems.length > 0) { + + if (this.config.showPublishDate) { + var timestamp = document.createElement("div"); + timestamp.className = "light small dimmed"; + timestamp.innerHTML = this.capitalizeFirstLetter(moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow() + ':'); + wrapper.appendChild(timestamp); + } + + var title = document.createElement("div"); + title.className = "bright medium light"; + title.innerHTML = this.newsItems[this.activeItem].title; + wrapper.appendChild(title); + + } else { + wrapper.innerHTML = "Loading news ..."; + wrapper.className = "small dimmed"; + } + + return wrapper; + }, + + /* fetchNews(compliments) + * Requests new data from news proxy. + */ + fetchNews: function() { + var url = this.config.proxyUrl + encodeURIComponent(this.config.feedUrl); + var self = this; + + var newsRequest = new XMLHttpRequest(); + newsRequest.open("GET", url, true); + newsRequest.onreadystatechange = function() { + if(this.readyState === 4) { + if(this.status === 200) { + self.newsItems = JSON.parse(this.response); + + if (!self.loaded) { + self.scheduleUpdateInterval(); + } + + self.loaded = true; + } else { + Log.error(self.name + ": Could not load news."); + } + + self.scheduleFetch((self.loaded) ? -1 : self.config.retryDelay); + + } + }; + newsRequest.send(); + }, + + /* scheduleUpdateInterval() + * Schedule visual update. + */ + scheduleUpdateInterval: function() { + var self = this; + + self.updateDom(self.config.animationSpeed); + + setInterval(function() { + self.activeItem++; + self.updateDom(self.config.animationSpeed); + }, this.config.updateInterval); + }, + + /* scheduleFetch() + * Schedule next news fetch. + * + * argument delay number - Milliseconds before next update. If empty, this.config.reloadInterval is used. + */ + scheduleFetch: function(delay) { + var nextLoad = this.config.reloadInterval; + if (typeof delay !== 'undefined' && delay >= 0) { + nextLoad = delay; + } + + var self = this; + clearTimeout(this.fetchTimer); + this.fetchTimer = setTimeout(function() { + self.fetchNews(); + }, nextLoad); + }, + + /* capitalizeFirstLetter(string) + * Capitalizes the first character of a string. + * + * argument string string - Input string. + * + * return string - Capitalized output string. + */ + capitalizeFirstLetter: function(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + } +}); + + diff --git a/modules/newsfeed/node_helper.js b/modules/newsfeed/node_helper.js new file mode 100644 index 00000000..cfe00e41 --- /dev/null +++ b/modules/newsfeed/node_helper.js @@ -0,0 +1,74 @@ +// Configuration. +var config = { + port: 8080 +}; + +// Load modules. +var express = require('express'); +var request = require('request'); +var FeedMe = require('feedme'); +var validUrl = require('valid-url'); +var app = express(); + +// Create NewsFetcher. +var NewsFetcher = (function() { + var self = this; + + self.successCallback = function(){}; + self.errorCallback = function(){}; + + self.items = []; + + var parser = new FeedMe(); + + parser.on('item', function(item) { + //console.log(item); + self.items.push({ + title: item.title, + pubdate: item.pubdate, + }); + }); + + parser.on('end', function(item) { + self.successCallback(self.items); + }); + + parser.on('error', function(item) { + self.errorCallback(); + }); + + return { + fetchNews: function(url, success, error) { + self.successCallback = success; + self.errorCallback = error; + request(url).pipe(parser); + } + }; +})(); + +// Create route for fetcher. +app.get('/', function (req, res) { + + if (!validUrl.isUri(req.query.url)){ + res.status(404).send('No valid feed URL.'); + return; + } + + NewsFetcher.fetchNews(req.query.url, function(items) { + res.send(items); + }, function() { + res.status(400).send('Could not parse feed.'); + }); +}); + +// Listen on port. +app.listen(config.port, function () { + console.log('Feed proxy is running on port: ' + config.port); +}); + +console.log('Starting feed proxy on port: ' + config.port); + + + + + diff --git a/package.json b/package.json index 9df003f5..2ed940dd 100755 --- a/package.json +++ b/package.json @@ -1,32 +1,36 @@ { - "name": "Magic-Mirror", - "version": "2.0.0", - "description": "A modular interface for smart mirrors.", - "main": "js/electron.js", - "scripts": { - "start": "electron js/electron.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/MichMich/MagicMirror.git" - }, - "keywords": [ - "magic mirror", - "smart mirror", - "mirror UI", - "modular" - ], - "author": "Michael Teeuw", - "contributors": "https://github.com/MichMich/MagicMirror/graphs/contributors", - "license": "MIT", - "bugs": { - "url": "https://github.com/MichMich/MagicMirror/issues" - }, - "homepage": "https://github.com/MichMich/MagicMirror#readme", - "devDependencies": { - "electron-prebuilt": "latest" - }, - "dependencies": { - "walk": "latest" - } + "name": "Magic-Mirror", + "version": "2.0.0", + "description": "A modular interface for smart mirrors.", + "main": "js/electron.js", + "scripts": { + "start": "electron js/electron.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/MichMich/MagicMirror.git" + }, + "keywords": [ + "magic mirror", + "smart mirror", + "mirror UI", + "modular" + ], + "author": "Michael Teeuw", + "contributors": "https://github.com/MichMich/MagicMirror/graphs/contributors", + "license": "MIT", + "bugs": { + "url": "https://github.com/MichMich/MagicMirror/issues" + }, + "homepage": "https://github.com/MichMich/MagicMirror#readme", + "devDependencies": { + "electron-prebuilt": "latest" + }, + "dependencies": { + "express":"latest", + "request":"latest", + "walk": "latest", + "feedme": "latest", + "valid-url": "latest" + } } From 15856574d767b2cf7f0e64e8c79f9dff988d1193 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 29 Mar 2016 16:10:50 +0200 Subject: [PATCH 6/8] Add fade option to weather forecast. --- modules/weatherforecast/weatherforecast.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/weatherforecast/weatherforecast.js b/modules/weatherforecast/weatherforecast.js index a6ff08ef..47ac33db 100644 --- a/modules/weatherforecast/weatherforecast.js +++ b/modules/weatherforecast/weatherforecast.js @@ -18,6 +18,8 @@ Module.create({ animationSpeed: 1000, timeFormat: config.timeFormat, lang: config.language, + fade: true, + fadePoint: 0.25, // Start on 1/4th of the list. initialLoadDelay: 5000, // 5 seconds delay. This delay is used to keep the OpenWeather API happy. retryDelay: 2500, @@ -129,6 +131,21 @@ Module.create({ minTempCell.className = 'align-right min-temp'; row.appendChild(minTempCell); + + if (this.config.fade && this.config.fadePoint < 1) { + if (this.config.fadePoint < 0) { + this.config.fadePoint = 0; + } + var startingPoint = this.forecast.length * this.config.fadePoint; + var steps = this.forecast.length - startingPoint; + if (f >= startingPoint) { + var currentStep = f - startingPoint; + row.style.opacity = 1 - (1 / steps * currentStep); + } + } + + + } From 899d05bc3295bd3e8191952e3e28343bc168a863 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Wed, 30 Mar 2016 12:20:46 +0200 Subject: [PATCH 7/8] Add server (web/socket), create socket system, better helper loader. - The Magic Mirror is now hosted via a express server, allowing you to load it from an external client (for debugging.) - It now includes a socket system to communicate between the node_helper and the client module. - node_helpers are now only loaded if the module is configured in the config. --- README.md | 6 +- config/config.js.sample | 7 +- index.html | 2 + js/defaults.js | 7 +- js/electron.js | 153 ++++++++++++++++---------- js/module.js | 37 ++++++- js/server.js | 83 ++++++++++++++ js/socket.js | 40 +++++++ js/socketclient.js | 83 ++++++++++++++ modules/newsfeed/newsfeed.js | 73 ++++--------- modules/newsfeed/node_helper.js | 187 +++++++++++++++++++++++++------- package.json | 5 +- 12 files changed, 531 insertions(+), 152 deletions(-) create mode 100644 js/server.js create mode 100644 js/socket.js create mode 100644 js/socketclient.js diff --git a/README.md b/README.md index 7d70cb88..5d5ffcdf 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,7 @@ Things that still have to be implemented or changed. ####Loader - Loading of module uses `eval()`. We might want to look into a better solution. [loader.js#L112](https://github.com/MichMich/MagicMirror/blob/v2-beta/js/loader.js#L112). -####Helper scripts -- Only start helper scripts of modules that are actually loaded in the UI (config.js) -- Notification system, so that not every helper scripts needs it's own socket to the UI. -- `modules/newsfeed/node_helper.js` now spawns it's own epxress webserver on port 8080. We need to create a solution for every module that needs a server side url. + + diff --git a/config/config.js.sample b/config/config.js.sample index 9e301459..03059a38 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -7,6 +7,7 @@ */ var config = { + port: 80, language: 'en', timeFormat: 24, @@ -47,4 +48,8 @@ var config = { }, ] -}; \ No newline at end of file +}; + + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== 'undefined') {module.exports = config;} \ No newline at end of file diff --git a/index.html b/index.html index 23cf889e..70b73040 100644 --- a/index.html +++ b/index.html @@ -27,6 +27,7 @@

+ @@ -34,6 +35,7 @@ + diff --git a/js/defaults.js b/js/defaults.js index 97ac99f0..33707784 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -8,6 +8,7 @@ */ var defaults = { + port: 80, language: 'en', timeFormat: 24, @@ -50,4 +51,8 @@ var defaults = { modules: 'modules', vendor: 'vendor' }, -}; \ No newline at end of file +}; + + +/*************** DO NOT EDIT THE LINE BELOW ***************/ +if (typeof module !== 'undefined') {module.exports = defaults;} \ No newline at end of file diff --git a/js/electron.js b/js/electron.js index cd2a4179..1ce98a0e 100755 --- a/js/electron.js +++ b/js/electron.js @@ -1,10 +1,15 @@ 'use strict'; -//for searching modules +//load modules const walk = require('walk'); +const fs = require('fs'); +const Server = require(__dirname + '/server.js'); const spawn = require('child_process').spawn; - const electron = require('electron'); + + +// Config +var config = {}; // Module to control application life. const app = electron.app; // Module to create native browser window. @@ -15,79 +20,115 @@ const BrowserWindow = electron.BrowserWindow; let mainWindow; function createWindow () { - // Create the browser window. - mainWindow = new BrowserWindow({width: 800, height: 600, fullscreen: true, "auto-hide-menu-bar": true, "node-integration": false}); + // Create the browser window. + mainWindow = new BrowserWindow({width: 800, height: 600, fullscreen: true, "auto-hide-menu-bar": true, "node-integration": false}); - // and load the index.html of the app. - mainWindow.loadURL('file://' + __dirname + '../../index.html'); + // and load the index.html of the app. + //mainWindow.loadURL('file://' + __dirname + '../../index.html'); + mainWindow.loadURL('http://localhost:' + config.port); - // Open the DevTools. - //mainWindow.webContents.openDevTools(); + // Open the DevTools. + //mainWindow.webContents.openDevTools(); - // Emitted when the window is closed. - mainWindow.on('closed', function() { - // Dereference the window object, usually you would store windows - // in an array if your app supports multi windows, this is the time - // when you should delete the corresponding element. - mainWindow = null; - }); + // Emitted when the window is closed. + mainWindow.on('closed', function() { + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow = null; + }); } -//Walk module folder and get file names -var module_loader = walk.walk(__dirname + '/../modules', { followLinks: false }); +function loadConfig (callback) { + console.log("Loading config ..."); + var defaults = require(__dirname + '/defaults.js'); + var configFilename = __dirname + '/../config/config.js'; -//for each file in modules -module_loader.on('file', function(root, stat, next) { - //if file is called node_helper.js load it - if (stat.name == "node_helper.js"){ - var module = (root + '/' + stat.name).split("/"); - var moduleName = module[module.length-2]; + try { + fs.accessSync(configFilename, fs.R_OK); + var c = require(configFilename); + var config = Object.assign(defaults, c); + callback(config); + } catch (e) { + callback(defaults); + } +} - //start module as child - var child = spawn('node', [root + '/' + stat.name]) +function loadModule(moduleName) { + var helperPath = __dirname + '/../modules/' + moduleName + '/node_helper.js'; - // Make sure the output is logged. - child.stdout.on('data', function(data) { - process.stdout.write(moduleName + ': ' + data); - }); + try { + fs.accessSync(helperPath, fs.R_OK); - child.stderr.on('data', function(data) { - process.stdout.write(moduleName + ': ' + data); - }); - - child.on('close', function(code) { - console.log(moduleName + ' closing code: ' + code); - }); + var child = spawn('node', [helperPath]); + // Make sure the output is logged. + child.stdout.on('data', function(data) { + process.stdout.write('[' + moduleName + '] ' + data); + }); - //Log module name - - console.log("Started helper script for module " + moduleName + "."); - } - next(); + child.stderr.on('data', function(data) { + process.stdout.write('[' + moduleName + '] ' + data); + }); + + child.on('close', function(code) { + console.log(moduleName + ' closing code: ' + code); + }); + + //Log module name + console.log("Started helper script for module: " + moduleName + "."); + + } catch (e) { + console.log("No helper found for module: " + moduleName + "."); + } +} + +function loadModules(modules) { + console.log("Loading module helpers ..."); + + for (var m in modules) { + loadModule(modules[m]); + } + + console.log("All module helpers loaded."); +} + +loadConfig(function(c) { + config = c; + + var modules = []; + + for (var m in config.modules) { + var module = config.modules[m]; + if (modules.indexOf(module.module) === -1) { + modules.push(module.module); + } + } + + loadModules(modules); }); -module_loader.on('end', function() { - console.log("All helpers started."); -}); - // This method will be called when Electron has finished // initialization and is ready to create browser windows. -app.on('ready', createWindow); +app.on('ready', function() { + var server = new Server(config, function() { + createWindow(); + }); +}); // Quit when all windows are closed. app.on('window-all-closed', function () { - // On OS X it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (process.platform !== 'darwin') { - app.quit(); - } + // On OS X it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + if (process.platform !== 'darwin') { + app.quit(); + } }); app.on('activate', function () { - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (mainWindow === null) { - createWindow(); - } + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (mainWindow === null) { + createWindow(); + } }); diff --git a/js/module.js b/js/module.js index e18c6e61..34ae02e6 100644 --- a/js/module.js +++ b/js/module.js @@ -88,7 +88,15 @@ var Module = Class.extend({ } }, - + /* socketNotificationReceived(notification, payload) + * This method is called when a socket notification arrives. + * + * argument notification string - The identifier of the noitication. + * argument payload mixed - The payload of the notification. + */ + socketNotificationReceived: function(notification, payload) { + Log.log(this.name + ' received a socket notification: ' + notification + ' - Payload: ' + payload); + }, @@ -118,6 +126,23 @@ var Module = Class.extend({ this.config = Object.assign(this.defaults, config); }, + /* socket() + * Returns a socket object. If it doesn't exsist, it's created. + * It also registers the notification callback. + */ + socket: function() { + if (typeof this._socket === 'undefined') { + this._socket = this._socket = new MMSocket(this.name); + } + + var self = this; + this._socket.setNotificationCallback(function(notification, payload) { + self.socketNotificationReceived(notification, payload); + }); + + return this._socket; + }, + /* file(file) * Retrieve the path to a module fike. * @@ -170,6 +195,16 @@ var Module = Class.extend({ */ sendNotification: function(notification, payload) { MM.sendNotification(notification, payload, this); + }, + + /* sendSocketNotification(notification, payload) + * Send a socket notification to the node helper. + * + * argument notification string - The identifier of the noitication. + * argument payload mixed - The payload of the notification. + */ + sendSocketNotification: function(notification, payload) { + this.socket().sendNotification(notification, payload); } }); diff --git a/js/server.js b/js/server.js new file mode 100644 index 00000000..32670a46 --- /dev/null +++ b/js/server.js @@ -0,0 +1,83 @@ +/* Magic Mirror + * Server + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + +var express = require('express'); +var app = require('express')(); +var server = require('http').Server(app); +var io = require('socket.io')(server); +var path = require('path'); + +var Server = function(config, callback) { + + /* createNamespace(namespace) + * Creates a namespace with a wildcard event. + * + * argument namespace string - The name of the namespace. + */ + var createNamespace = function(namespace) { + console.log('Creating socket namespace: ' + namespace); + + io.of(namespace).on('connection', function (socket) { + console.log("New socket connection on namespace: " + namespace); + + // add a catch all event. + var onevent = socket.onevent; + socket.onevent = function (packet) { + var args = packet.data || []; + onevent.call (this, packet); // original call + packet.data = ["*"].concat(args); + onevent.call(this, packet); // additional call to catch-all + }; + + // register catch all. + socket.on('*', function (event, data) { + io.of(namespace).emit(event, data); + }); + }); + }; + + /* createNamespaces() + * Creates a namespace for all modules in the config. + */ + var createNamespaces = function() { + var modules = []; + var m; + + for (m in config.modules) { + var module = config.modules[m]; + if (modules.indexOf(module.module) === -1) { + modules.push(module.module); + } + } + + for (m in modules) { + createNamespace(modules[m]); + } + }; + + console.log("Starting server op port " + config.port + " ... "); + + server.listen(config.port); + app.use('/js', express.static(__dirname)); + app.use('/config', express.static(path.resolve(__dirname + '/../config'))); + app.use('/css', express.static(path.resolve(__dirname + '/../css'))); + app.use('/fonts', express.static(path.resolve(__dirname + '/../fonts'))); + app.use('/modules', express.static(path.resolve(__dirname + '/../modules'))); + app.use('/vendor', express.static(path.resolve(__dirname + '/../vendor'))); + + app.get('/', function (req, res) { + res.sendFile(path.resolve(__dirname + '/../index.html')); + }); + + createNamespaces(); + + if (typeof callback === 'function') { + callback(); + } +}; + +module.exports = Server; \ No newline at end of file diff --git a/js/socket.js b/js/socket.js new file mode 100644 index 00000000..4badc5f8 --- /dev/null +++ b/js/socket.js @@ -0,0 +1,40 @@ +/* exported Log */ + +/* Magic Mirror + * Socket Connection + * + * By Michael Teeuw http://michaelteeuw.nl + * MIT Licensed. + */ + + + +var MMSocket = function(moduleName) { + + var self = this; + + if (typeof moduleName !== 'string') { + throw new Error('Please set the module name for the MMSocket.'); + } + + self.moduleName = moduleName; + + + self.socket = io('http://localhost:8080'); + self.socket.on('notification', function (data) { + MM.sendNotification(data.notification, data.payload, Socket); + }); + + return { + sendMessage: function(notification, payload, sender) { + Log.log('Send socket message: ' + notification); + self.socket.emit('notification', { + notification: notification, + sender: sender, + payload: payload + }); + } + }; +}; + + \ No newline at end of file diff --git a/js/socketclient.js b/js/socketclient.js new file mode 100644 index 00000000..a3cb57bd --- /dev/null +++ b/js/socketclient.js @@ -0,0 +1,83 @@ +if (typeof window === 'undefined') { + // Only perfom this part if is isn't running in the browser. + + // Load socket client + var io = require('socket.io-client'); + + // Load config + var fs = require('fs'); + + var config = {}; + + var defaults = require(__dirname + '/defaults.js'); + var configFilename = __dirname + '/../config/config.js'; + + try { + fs.accessSync(configFilename, fs.R_OK); + var c = require(configFilename); + config = Object.assign(defaults, c); + } catch (e) { + config = defaults; + } +} + + +var MMSocket = function(moduleName) { + + var self = this; + + if (typeof moduleName !== 'string') { + throw new Error('Please set the module name for the MMSocket.'); + } + + self.moduleName = moduleName; + + // Private Methods + var socketBase = (typeof window === 'undefined') ? 'http://localhost:'+config.port : ''; + socket = io(socketBase + '/' + self.moduleName); + + var notificationCallback = function() {}; + + socket.on('connect', function(s) { + + // add a catch all event. + var onevent = socket.onevent; + socket.onevent = function (packet) { + var args = packet.data || []; + onevent.call (this, packet); // original call + packet.data = ["*"].concat(args); + onevent.call(this, packet); // additional call to catch-all + }; + + // register catch all. + socket.on('*', function (notification, payload) { + if (notification !== '*') { + //console.log('Received notification: ' + notification +', payload: ' + payload); + notificationCallback(notification, payload); + } + }); + + + }); + + var sendNotification = function(notification, payload) { + //console.log('Send notification: ' + notification +', payload: ' + payload); + socket.emit(notification, payload); + }; + + // Public Methods + this.setNotificationCallback = function(callback) { + notificationCallback = callback; + }; + + this.sendNotification = function(notification, payload) { + if (typeof payload === 'undefined') { + payload = {}; + } + sendNotification(notification, payload); + }; +}; + +if (typeof module !== 'undefined') { + module.exports = MMSocket; +} \ No newline at end of file diff --git a/modules/newsfeed/newsfeed.js b/modules/newsfeed/newsfeed.js index f4bbccd7..2c84eda8 100644 --- a/modules/newsfeed/newsfeed.js +++ b/modules/newsfeed/newsfeed.js @@ -16,11 +16,6 @@ Module.create({ reloadInterval: 10 * 60 * 1000, // every 10 minutes updateInterval: 7.5 * 1000, animationSpeed: 2.5 * 1000, - - - proxyUrl: 'http://localhost:8080/?url=', - initialLoadDelay: 0, // 5 seconds delay. This delay is used to keep the OpenWeather API happy. - retryDelay: 2500, }, // Define required scripts. @@ -37,14 +32,28 @@ Module.create({ this.newsItems = []; this.loaded = false; - this.scheduleFetch(this.config.initialLoadDelay); - - this.fetchTimer = null; this.activeItem = 0; + + this.fetchNews(); + }, + + // Override socket notification handler. + socketNotificationReceived: function(notification, payload) { + if (notification === 'NEWS_ITEMS') { + if (payload.url === this.config.feedUrl) { + this.newsItems = payload.items; + if (!this.loaded) { + this.scheduleUpdateInterval(); + } + + this.loaded = true; + } + } }, // Override dom generator. getDom: function() { + var wrapper = document.createElement("div"); if (this.activeItem >= this.newsItems.length) { @@ -57,6 +66,7 @@ Module.create({ var timestamp = document.createElement("div"); timestamp.className = "light small dimmed"; timestamp.innerHTML = this.capitalizeFirstLetter(moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow() + ':'); + //timestamp.innerHTML = this.config.feedUrl; wrapper.appendChild(timestamp); } @@ -77,30 +87,11 @@ Module.create({ * Requests new data from news proxy. */ fetchNews: function() { - var url = this.config.proxyUrl + encodeURIComponent(this.config.feedUrl); - var self = this; - - var newsRequest = new XMLHttpRequest(); - newsRequest.open("GET", url, true); - newsRequest.onreadystatechange = function() { - if(this.readyState === 4) { - if(this.status === 200) { - self.newsItems = JSON.parse(this.response); - - if (!self.loaded) { - self.scheduleUpdateInterval(); - } - - self.loaded = true; - } else { - Log.error(self.name + ": Could not load news."); - } - - self.scheduleFetch((self.loaded) ? -1 : self.config.retryDelay); - - } - }; - newsRequest.send(); + Log.log('Add news feed to fetcher: ' + this.config.feedUrl); + this.sendSocketNotification('ADD_FEED', { + url: this.config.feedUrl, + reloadInterval: this.config.reloadInterval + }); }, /* scheduleUpdateInterval() @@ -117,24 +108,6 @@ Module.create({ }, this.config.updateInterval); }, - /* scheduleFetch() - * Schedule next news fetch. - * - * argument delay number - Milliseconds before next update. If empty, this.config.reloadInterval is used. - */ - scheduleFetch: function(delay) { - var nextLoad = this.config.reloadInterval; - if (typeof delay !== 'undefined' && delay >= 0) { - nextLoad = delay; - } - - var self = this; - clearTimeout(this.fetchTimer); - this.fetchTimer = setTimeout(function() { - self.fetchNews(); - }, nextLoad); - }, - /* capitalizeFirstLetter(string) * Capitalizes the first character of a string. * diff --git a/modules/newsfeed/node_helper.js b/modules/newsfeed/node_helper.js index cfe00e41..f1423736 100644 --- a/modules/newsfeed/node_helper.js +++ b/modules/newsfeed/node_helper.js @@ -1,17 +1,142 @@ -// Configuration. -var config = { - port: 8080 -}; // Load modules. -var express = require('express'); var request = require('request'); var FeedMe = require('feedme'); var validUrl = require('valid-url'); -var app = express(); +var MMSocket = require('../../js/socketclient.js'); +var socket = new MMSocket('newsfeed'); -// Create NewsFetcher. -var NewsFetcher = (function() { +var fetchers = {}; + +// Register the notification callback. +socket.setNotificationCallback(function(notification, payload) { + if(notification === 'ADD_FEED') { + createFetcher(payload.url, payload.reloadInterval); + } +}); + +/* createFetcher(url, reloadInterval) + * Creates a fetcher for a new url if it doesn't exsist yet. + * Otherwise it reoses the exsisting one. + * + * attribute url string - URL of the news feed. + * attribute reloadInterval number - Reload interval in milliseconds. + */ + +var createFetcher = function(url, reloadInterval) { + if (!validUrl.isUri(url)){ + socket.sendNotification('INCORRECT_URL', url); + return; + } + + var fetcher; + if (typeof fetchers[url] === 'undefined') { + console.log('Create new news fetcher for url: ' + url + ' - Interval: ' + reloadInterval); + fetcher = new Fetcher(url, reloadInterval); + fetchers[url] = fetcher; + } else { + console.log('Use exsisting news fetcher for url: ' + url); + fetcher = fetchers[url]; + fetcher.setReloadInterval(reloadInterval); + fetcher.broadcastItems(); + } + + fetcher.startFetch(); +}; + + +/* Fetcher + * Responsible for requesting an update on the set interval and broadcasting the data. + * + * attribute url string - URL of the news feed. + * attribute reloadInterval number - Reload interval in milliseconds. + */ + +var Fetcher = function(url, reloadInterval) { + var self = this; + var newsFetcher = new NewsFetcher(); + if (reloadInterval < 1000) { + reloadInterval = 1000; + } + + var reloadTimer = null; + var items = []; + + /* private methods */ + + /* fetchNews() + * Request the new items from the newsFetcher. + */ + + var fetchNews = function() { + //console.log('Fetch news.'); + clearTimeout(reloadTimer); + reloadTimer = null; + newsFetcher.fetchNews(url, function(fetchedItems) { + //console.log(fetchedItems.length + ' items received.'); + items = fetchedItems; + self.broadcastItems(); + scheduleTimer(); + }, function(error) { + //console.log('Unable to load news: ' + error); + socket.sendNotification('UNABLE_TO_LOAD_NEWS', {url:url, error:error}); + scheduleTimer(); + }); + }; + + /* scheduleTimer() + * Schedule the timer for the next update. + */ + + var scheduleTimer = function() { + //console.log('Schedule update timer.'); + clearTimeout(reloadTimer); + reloadTimer = setTimeout(function() { + fetchNews(); + }, reloadInterval); + }; + + /* public methods */ + + /* setReloadInterval() + * Update the reload interval, but only if we need to increase the speed. + * + * attribute interval number - Interval for the update in milliseconds. + */ + this.setReloadInterval = function(interval) { + if (interval > 1000 && interval < reloadInterval) { + reloadInterval = interval; + } + }; + + /* startFetch() + * Initiate fetchNews(); + */ + this.startFetch = function() { + fetchNews(); + }; + + /* broadcastItems() + * Broadcast the exsisting items. + */ + this.broadcastItems = function() { + if (items.length <= 0) { + //console.log('No items to broadcast yet.'); + return; + } + //console.log('Broadcasting ' + items.length + ' items.'); + socket.sendNotification('NEWS_ITEMS', { + url: url, + items: items + }); + }; +}; + +/* NewsFetcher + * Responsible for requesting retrieving the data. + */ + +var NewsFetcher = function() { var self = this; self.successCallback = function(){}; @@ -33,41 +158,27 @@ var NewsFetcher = (function() { self.successCallback(self.items); }); - parser.on('error', function(item) { - self.errorCallback(); + parser.on('error', function(error) { + self.errorCallback(error); }); - return { - fetchNews: function(url, success, error) { - self.successCallback = success; - self.errorCallback = error; - request(url).pipe(parser); - } + /* public methods */ + + /* fetchNews() + * Fetch the new news items. + * + * attribute url string - The url to fetch. + * attribute success function(items) - Callback on succes. + * attribute error function(error) - Callback on error. + */ + self.fetchNews = function(url, success, error) { + self.successCallback = success; + self.errorCallback = error; + request(url).pipe(parser); }; -})(); +}; -// Create route for fetcher. -app.get('/', function (req, res) { - if (!validUrl.isUri(req.query.url)){ - res.status(404).send('No valid feed URL.'); - return; - } - - NewsFetcher.fetchNews(req.query.url, function(items) { - res.send(items); - }, function() { - res.status(400).send('Could not parse feed.'); - }); -}); - -// Listen on port. -app.listen(config.port, function () { - console.log('Feed proxy is running on port: ' + config.port); -}); - -console.log('Starting feed proxy on port: ' + config.port); - diff --git a/package.json b/package.json index 2ed940dd..61a1c64c 100755 --- a/package.json +++ b/package.json @@ -27,10 +27,13 @@ "electron-prebuilt": "latest" }, "dependencies": { + "socket.io":"latest", "express":"latest", "request":"latest", "walk": "latest", "feedme": "latest", - "valid-url": "latest" + "valid-url": "latest", + "ical": "latest", + "moment": "latest" } } From 1d4c1624c4815ba28ae4a111bb32c072ccecef79 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Wed, 30 Mar 2016 12:49:41 +0200 Subject: [PATCH 8/8] update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61a1c64c..96070afe 100755 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "Magic-Mirror", + "name": "magicmirror", "version": "2.0.0", "description": "A modular interface for smart mirrors.", "main": "js/electron.js",