├── README.MD ├── Serve ├── .gitignore ├── README.MD ├── api_router.js ├── app.js ├── bin │ └── www ├── config.js ├── controller │ ├── device.js │ └── sensor_value.js ├── models │ ├── device.js │ ├── index.js │ ├── sensor_value.js │ └── test_data.js ├── package.json └── redis.js ├── angular ├── .bowerrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .yo-rc.json ├── README.MD ├── bower.json ├── e2e │ ├── .eslintrc │ ├── main.po.js │ └── main.spec.js ├── gulp │ ├── .eslintrc │ ├── build.js │ ├── conf.js │ ├── e2e-tests.js │ ├── inject.js │ ├── scripts.js │ ├── server.js │ ├── styles.js │ ├── unit-tests.js │ └── watch.js ├── gulpfile.js ├── karma.conf.js ├── package.json ├── protractor.conf.js └── src │ ├── Cyborg.scss │ ├── app │ ├── app.js │ ├── app.resource.js │ ├── app.route.js │ ├── components │ │ └── navbar │ │ │ └── navbar.html │ ├── dashboard │ │ ├── dashboard.ctrl.js │ │ ├── dashboard.html │ │ └── dashboard.scss │ ├── index.scss │ └── my-device │ │ ├── my-device.ctrl.js │ │ ├── my-device.html │ │ └── my-device.scss │ ├── assets │ └── images │ │ └── temperature.png │ ├── favicon.ico │ └── index.html ├── doc ├── README.MD ├── img │ ├── dashboard.png │ ├── devices.png │ └── system.png ├── 答辩Slide show.key ├── 答辩Slide show.pdf ├── 论文.docx ├── 论文.pdf └── 论文草稿.png └── hardware ├── .gitignore ├── Makefile ├── Makefile-user.mk ├── README.MD ├── app ├── application.cpp └── led.cpp └── include ├── led.h └── user_config.h /README.MD: -------------------------------------------------------------------------------- 1 | # myIot 2 | 我的毕业设计,一个基于物联网的温度采集系统。ESP8266 WIFI芯片采集温度信息,服务器端使用Node.js 的Express框架编程实现,浏览器端展示温度曲线,使用Angular Js框架实现。 3 | 4 | ### 目录结构 5 | 6 | ``` 7 | . 8 | ├── README.md 9 | ├── server // 服务端目录 10 | ├── angular // angular端目录 11 | ├── doc // 毕设相关文档 12 | ├── hardware // ESP8266硬件端目录 13 | . 14 | ``` 15 | ## 系统概述 16 | ### 框图: 17 |  18 | ### [硬件端](https://github.com/nieheyong/myIot/tree/master/hardware) 19 | 温度信息采集主要使用 ESP8266 WIFI 芯片通过 DHT 22 传感器采集环境温度信息,通过WIFI将温度信息发往后台服务器。 20 | 21 | ### [服务端](https://github.com/nieheyong/myIot/tree/master/Serve) 22 | 23 | 后台服务器采用 Node.js 编程,使用Express框架,MongoDB和Redis数据库。为前端和温度信息采集硬件端提供 REST API 服务。 24 | 25 | ### [前端](https://github.com/nieheyong/myIot/tree/master/angular) 26 | 前端使用 AngularJS ,Chart.js 图表库可视化温 度数据,Bootstrap 作为样式库并提供响应式布局。通过 HTTP 协议获取后台的温度数据绘制温度曲线。支持实时温度曲线和历史温度查看。 27 | 28 | 29 | ## 界面效果 30 |  31 |  32 | -------------------------------------------------------------------------------- /Serve/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | DB/ 3 | dump.rdb 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /Serve/README.MD: -------------------------------------------------------------------------------- 1 | # Node.js服务端 2 | 服务端使用基于Node.js的Express框架,[MongoDB](https://www.mongodb.com/)以及[Redis](http://redis.io/)数据库。 3 | ### 开发 4 | 5 | ##### 安装项目及依赖 6 | ``` 7 | $ git clone https://github.com/nieheyong/myIot.git 8 | $ cd myIot/Serve 9 | $ npm install 10 | ``` 11 | ##### 运行 12 | 需要先运行[MongoDB](https://www.mongodb.com/)以及[Redis](http://redis.io/). 13 | ``` 14 | $ npm start 15 | ``` 16 | -------------------------------------------------------------------------------- /Serve/api_router.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var deviceController = require('./controller/device'); 3 | var sensorValueController = require('./controller/sensor_value'); 4 | var config = require('./config'); 5 | var router = express.Router(); 6 | 7 | // 传感器 8 | router.get('/devices', deviceController.get); 9 | router.post('/devices', deviceController.creat); 10 | 11 | router.get('/sensor/:sensor_id/value/history', sensorValueController.getHistory); 12 | router.get('/sensor/:sensor_id/value/realtime', sensorValueController.realTime); 13 | router.post('/sensor/:sensor_id/value', sensorValueController.post); 14 | 15 | 16 | module.exports = router; 17 | -------------------------------------------------------------------------------- /Serve/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var logger = require('morgan'); 4 | var bodyParser = require('body-parser'); 5 | var models=require('./models'); 6 | var apiRoute = require('./api_router'); 7 | 8 | var app = express(); 9 | 10 | app.use(logger('dev')); 11 | app.use(bodyParser.json()); 12 | app.use(bodyParser.urlencoded({ extended: false })); 13 | 14 | app.use(express.static(path.join(__dirname, '../angular/dist'))); 15 | 16 | 17 | app.all('*', function(req, res, next) { 18 | res.set('Access-Control-Allow-Origin', '*'); 19 | res.set('Access-Control-Allow-Credentials', true); 20 | res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT'); 21 | res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization'); 22 | if ('OPTIONS' == req.method) return res.send(200); 23 | next(); 24 | }); 25 | 26 | 27 | app.use('/api', apiRoute); 28 | 29 | // catch 404 and forward to error handler 30 | app.use(function(req, res, next) { 31 | var err = new Error('Not Found'); 32 | err.status = 404; 33 | next(err); 34 | }); 35 | 36 | // error handlers 37 | 38 | // development error handler 39 | // will print stacktrace 40 | if (app.get('env') === 'development') { 41 | app.use(function(err, req, res, next) { 42 | res.status(err.status || 500); 43 | res.render('error', { 44 | message: err.message, 45 | error: err 46 | }); 47 | }); 48 | } 49 | 50 | // production error handler 51 | // no stacktraces leaked to user 52 | app.use(function(err, req, res, next) { 53 | res.status(err.status || 500); 54 | res.json({ 55 | message: err.message, 56 | error: {} 57 | }); 58 | }); 59 | 60 | module.exports = app; 61 | -------------------------------------------------------------------------------- /Serve/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('myIot:server'); 9 | var http = require('http'); 10 | var logger = require('morgan'); 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | server.listen(port); 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | console.log(''); 91 | console.log('API is starting on http://localhost:3000'); 92 | console.log(''); 93 | } 94 | -------------------------------------------------------------------------------- /Serve/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * config 3 | */ 4 | 5 | 6 | var config = { 7 | // debug 为 true 时,用于本地调试 8 | debug: true, 9 | 10 | host: 'localhost', 11 | // mongodb 配置 12 | mongodb: 'mongodb://127.0.0.1/myIot', 13 | port: 3000 14 | }; 15 | 16 | module.exports = config; 17 | -------------------------------------------------------------------------------- /Serve/controller/device.js: -------------------------------------------------------------------------------- 1 | var Device=require('../models').Device; 2 | 3 | exports.get = function (req, res, next) { 4 | Device.find(function(err,devices){ 5 | if (err) throw err; 6 | res.json(devices); 7 | }); 8 | }; 9 | 10 | exports.creat = function (req, res, next) { 11 | Device.create(req.body.device,function(err,sensors){ 12 | if (err) throw err; 13 | res.json(sensors); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /Serve/controller/sensor_value.js: -------------------------------------------------------------------------------- 1 | var SensorValue = require('../models').SensorValue; 2 | var redisClient = require('../redis').redisClient; 3 | var _ = require('lodash'); 4 | 5 | 6 | exports.get = function(req, res, next) { 7 | 8 | }; 9 | 10 | 11 | exports.getHistory = function(req, res, next) { 12 | var sensor_id = req.params.sensor_id; 13 | var start = req.query.start || 0; 14 | var end = req.query.end || 0; 15 | 16 | SensorValue.find({ 17 | sensor_id: sensor_id 18 | }) 19 | //.limit(336) 20 | .select('value timestamp') 21 | .where('timestamp').gte(start).lte(end) 22 | .sort('timestamp') 23 | .exec(function(err, sensorValues) { 24 | if (err) { 25 | return false; 26 | } 27 | res.json(sensorValues); 28 | }); 29 | 30 | }; 31 | 32 | var forever = 4100688000000; //2099-12-12 33 | 34 | exports.post = function(req, res, next) { 35 | var sensor_id = Number(req.params.sensor_id); 36 | var value = req.body.value; 37 | 38 | 39 | var timestamp = new Date().getTime(); 40 | 41 | redisClient.zadd(sensor_id, timestamp, (timestamp * 10000) + value, function(err, response) { 42 | if (err) throw err; 43 | console.log('added ' + response + ' items.'); 44 | }); 45 | 46 | redisClient.zremrangebyscore(sensor_id, 0, timestamp - tenMin, function(err, response) { 47 | if (err) throw err; 48 | console.log('removeAll ' + response + ' items.'); 49 | }); 50 | 51 | if (req.body.save) { 52 | SensorValue.create({ 53 | sensor_id: sensor_id, 54 | value: value 55 | }, function(err, sensors) { 56 | if (err) { 57 | return false; 58 | } 59 | res.json(sensors); 60 | }); 61 | } else { 62 | res.send({ 63 | success: true 64 | }); 65 | } 66 | }; 67 | 68 | 69 | var tenMin = 60*10 * 1000; 70 | exports.realTime = function(req, res, next) { 71 | var sensor_id = Number(req.params.sensor_id);//获取传感器ID 72 | var latsTimestamp = Number(req.query.latsTimestamp) || 0;//上次获取数据的时间戳 73 | var timestamp = new Date().getTime();//当前时间戳 74 | //移除十分钟之前的数据 75 | redisClient.zremrangebyscore(sensor_id, 0, timestamp - tenMin, function(err, response) { 76 | if (err) throw err; 77 | console.log('removeAll ' + response + ' items.'); 78 | //获取最新的数据 79 | redisClient.zrangebyscore(sensor_id, latsTimestamp + 1, forever, function(err, response) { 80 | if (err) throw err; 81 | 82 | var timestamp = parseInt(_.last(response) / 10000); 83 | _.each(response, function(data, index) { 84 | response[index] = response[index] % 10000; 85 | }); 86 | res.json({ 87 | data: response, 88 | latsTimestamp: timestamp 89 | }); 90 | }); 91 | }); 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /Serve/models/device.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | 4 | var SensorSchema = new Schema({ 5 | sensor_id: { type: Number }, 6 | name: { type: String,default:'temperature sensor'}, 7 | sensor_type: { type: String } 8 | }); 9 | 10 | var DeviceSchema = new Schema({ 11 | device_id:{type:Number,index:true,unique:true}, 12 | name:{type:String}, 13 | profile:{type: String,default:''}, 14 | create_at: { type: Number, default: new Date().getTime() }, 15 | sensors:[SensorSchema] 16 | }); 17 | 18 | mongoose.model('Device', DeviceSchema); 19 | -------------------------------------------------------------------------------- /Serve/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var config = require('../config'); 3 | 4 | mongoose.connect(config.mongodb, { 5 | server: {poolSize: 20} 6 | }, function (err) { 7 | if (err) { 8 | console.log('connect to %s error: ', config.db, err.message); 9 | process.exit(1); 10 | }else { 11 | console.log('connect to mongodb success'); 12 | require('./test_data'); 13 | } 14 | }); 15 | 16 | // models 17 | require('./device'); 18 | require('./sensor_value'); 19 | 20 | exports.Device = mongoose.model('Device'); 21 | exports.SensorValue = mongoose.model('SensorValue'); 22 | -------------------------------------------------------------------------------- /Serve/models/sensor_value.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | 4 | var SensorValueSchema = new Schema({ 5 | sensor_id: { type: Number }, 6 | value: { type: Number}, 7 | timestamp:{type: Number, default: new Date().getTime()} 8 | }); 9 | 10 | mongoose.model('SensorValue', SensorValueSchema); -------------------------------------------------------------------------------- /Serve/models/test_data.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var _ = require('lodash'); 3 | 4 | mongoose.model('Device').find({ 5 | device_id: 1 6 | }, function(err, devices) { 7 | if (err) throw err; 8 | if (!devices.length) { 9 | insertTestData(); 10 | } 11 | }); 12 | 13 | function insertTestData() { 14 | 15 | //插入四个测试设备 16 | var device1 = { 17 | device_id: 1, 18 | name: "教室的传感器", 19 | profile: "测量教室的温度", 20 | sensors: [{ 21 | sensor_id: 11, 22 | name: "wendu", 23 | sensor_type: "温度传感器" 24 | }] 25 | }; 26 | var device2 = { 27 | device_id: 2, 28 | name: "宿舍的传感器", 29 | profile: "测量宿舍的温度", 30 | sensors: { 31 | sensor_id: 21, 32 | name: "wendu", 33 | sensor_type: "温度传感器" 34 | } 35 | }; 36 | var device3 = { 37 | device_id: 3, 38 | name: "仓库的传感器", 39 | profile: "测量仓库的温度", 40 | sensors: { 41 | sensor_id: 31, 42 | name: "wendu", 43 | sensor_type: "温度传感器" 44 | } 45 | }; 46 | var device4 = { 47 | device_id: 4, 48 | name: "车间的传感器", 49 | profile: "测量车间的温度", 50 | sensors: { 51 | sensor_id: 41, 52 | name: "wendu", 53 | sensor_type: "温度传感器" 54 | } 55 | }; 56 | mongoose.model('Device').create([device1, device2, device3, device4]); 57 | 58 | // 插入四个传感器的历史数据,传感器数值随机生成,历史日期为2016-7-1前10天 59 | var sensorIDs = [11, 21, 31, 41]; 60 | _.each(sensorIDs, function(id) { 61 | var timestamp = 1467302400 * 1000; // 2016/7/1 0:0:0 0ms 62 | var count = 24 * 10; //10天的数据 63 | for (var i = 0; i < count; i++) { 64 | mongoose.model('SensorValue').create({ 65 | sensor_id: id, 66 | value: _.random(-10, 42.2), 67 | timestamp: timestamp 68 | }, function(err, sensors) { 69 | if (err) { 70 | return false; 71 | } 72 | }); 73 | timestamp = timestamp - 3600 * 1000; //一小时一个数据点 74 | } 75 | }); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /Serve/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "dev": "supervisor debug ./bin/www", 8 | "mongo": "mongod --dbpath ./DB" 9 | }, 10 | "dependencies": { 11 | "body-parser": "~1.13.2", 12 | "debug": "~2.2.0", 13 | "express": "^4.13.4", 14 | "lodash": "^4.6.1", 15 | "mongoose": "^4.4.4", 16 | "morgan": "~1.6.1", 17 | "redis": "^2.5.3", 18 | "serve-favicon": "~2.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Serve/redis.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | var redisClient = redis.createClient(6379); 3 | 4 | redisClient.on('error', function (err) { 5 | console.log('Error ' + err); 6 | }); 7 | 8 | redisClient.on('connect', function () { 9 | console.log('Redis is ready'); 10 | }); 11 | 12 | exports.redis = redis; 13 | exports.redisClient = redisClient; 14 | -------------------------------------------------------------------------------- /angular/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /angular/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "plugins": ["angular"], 4 | "env": { 5 | "browser": true, 6 | "jasmine": true 7 | }, 8 | "globals": { 9 | "angular": true, 10 | "module": true, 11 | "inject": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /angular/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | coverage/ 4 | .sass-cache/ 5 | .idea/ 6 | .tmp/ 7 | dist/ 8 | -------------------------------------------------------------------------------- /angular/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-gulp-angular": { 3 | "version": "1.0.2", 4 | "props": { 5 | "angularVersion": "~1.4.2", 6 | "angularModules": [], 7 | "jQuery": { 8 | "key": "jquery2" 9 | }, 10 | "resource": { 11 | "key": "angular-resource", 12 | "module": "ngResource" 13 | }, 14 | "router": { 15 | "key": "ui-router", 16 | "module": "ui.router" 17 | }, 18 | "ui": { 19 | "key": "bootstrap", 20 | "module": null 21 | }, 22 | "bootstrapComponents": { 23 | "key": "angular-strap", 24 | "module": "mgcrea.ngStrap" 25 | }, 26 | "cssPreprocessor": { 27 | "key": "node-sass", 28 | "extension": "scss" 29 | }, 30 | "jsPreprocessor": { 31 | "key": "noJsPrepro", 32 | "extension": "js", 33 | "srcExtension": "js" 34 | }, 35 | "htmlPreprocessor": { 36 | "key": "noHtmlPrepro", 37 | "extension": "html" 38 | }, 39 | "foundationComponents": { 40 | "name": null, 41 | "version": null, 42 | "key": null, 43 | "module": null 44 | }, 45 | "paths": { 46 | "src": "src", 47 | "dist": "dist", 48 | "e2e": "e2e", 49 | "tmp": ".tmp" 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /angular/README.MD: -------------------------------------------------------------------------------- 1 | # 前端 2 | 前端使用AngularJS框架,UI-Router路由控制,ng-resource与后台API交互,Bootstrap的[Cyborg主题](https://bootswatch.com/cyborg/)作为样式库, 3 | [AngularStrap](http://mgcrea.github.io/angular-strap/)作为控件库, 4 | [Angular Chart图表库](http://jtblin.github.io/angular-chart.js/)显示曲线图. 5 | ### 开发 6 | 7 | ##### 先安装工具 `gulp` 和 `bower`: 8 | ``` 9 | $ npm install -g gulp bower 10 | ``` 11 | ##### 安装项目及依赖 12 | ``` 13 | $ git clone https://github.com/nieheyong/myIot.git 14 | $ cd myIot/angular 15 | $ npm install 16 | $ bower install 17 | ``` 18 | ##### 运行 19 | ``` 20 | $ gulp serve 21 | ``` 22 | 会在浏览器中自动打开 http://localhost:3000 23 | 24 | ## 生产环境构建 25 | 26 | ``` 27 | $ gulp build 28 | ``` 29 | ## 界面效果 30 |  31 |  32 | -------------------------------------------------------------------------------- /angular/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "jquery": "~2.1.4", 6 | "angular-resource": "~1.4.2", 7 | "angular-ui-router": "~0.2.15", 8 | "bootstrap-sass": "~3.3.5", 9 | "angular-strap": "~2.3.1", 10 | "animate.css": "~3.4.0", 11 | "angular": "~1.4.2", 12 | "angular-chart.js": "^0.9.0", 13 | "font-awesome": "^4.5.0" 14 | }, 15 | "devDependencies": { 16 | "angular-mocks": "~1.4.2" 17 | }, 18 | "overrides": { 19 | "bootstrap-sass": { 20 | "main": [ 21 | "assets/stylesheets/_bootstrap.scss", 22 | "assets/fonts/bootstrap/glyphicons-halflings-regular.eot", 23 | "assets/fonts/bootstrap/glyphicons-halflings-regular.svg", 24 | "assets/fonts/bootstrap/glyphicons-halflings-regular.ttf", 25 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff", 26 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff2" 27 | ] 28 | }, 29 | "font-awesome": { 30 | "main": [ 31 | "css/font-awesome.css", 32 | "fonts/FontAwesome.otf", 33 | "fonts/fontawesome-webfont.eot", 34 | "fonts/fontawesome-webfont.svg", 35 | "fonts/fontawesome-webfont.ttf", 36 | "fonts/fontawesome-webfont.woff", 37 | "fonts/fontawesome-webfont.woff2" 38 | ] 39 | } 40 | }, 41 | "resolutions": { 42 | "jquery": "~2.1.4", 43 | "angular": "~1.4.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /angular/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "browser": false, 4 | "element": false, 5 | "by": false, 6 | "$": false, 7 | "$$": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /angular/e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | this.jumbEl = element(by.css('.jumbotron')); 10 | this.h1El = this.jumbEl.element(by.css('h1')); 11 | this.imgEl = this.jumbEl.element(by.css('img')); 12 | this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in main.awesomeThings')); 13 | }; 14 | 15 | module.exports = new MainPage(); 16 | -------------------------------------------------------------------------------- /angular/e2e/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | beforeEach(function () { 7 | browser.get('/index.html'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | it('should include jumbotron with correct data', function() { 12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); 13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); 14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); 15 | }); 16 | 17 | it('should list more than 5 awesome things', function () { 18 | expect(page.thumbnailEls.count()).toBeGreaterThan(5); 19 | }); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /angular/gulp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /angular/gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var $ = require('gulp-load-plugins')({ 8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 9 | }); 10 | 11 | gulp.task('partials', function () { 12 | return gulp.src([ 13 | path.join(conf.paths.src, '/app/**/*.html'), 14 | path.join(conf.paths.tmp, '/serve/app/**/*.html') 15 | ]) 16 | .pipe($.minifyHtml({ 17 | empty: true, 18 | spare: true, 19 | quotes: true 20 | })) 21 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 22 | module: 'myIot', 23 | root: 'app' 24 | })) 25 | .pipe(gulp.dest(conf.paths.tmp + '/partials/')); 26 | }); 27 | 28 | gulp.task('html', ['inject', 'partials'], function () { 29 | var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false }); 30 | var partialsInjectOptions = { 31 | starttag: '', 32 | ignorePath: path.join(conf.paths.tmp, '/partials'), 33 | addRootSlash: false 34 | }; 35 | 36 | var htmlFilter = $.filter('*.html', { restore: true }); 37 | var jsFilter = $.filter('**/*.js', { restore: true }); 38 | var cssFilter = $.filter('**/*.css', { restore: true }); 39 | var assets; 40 | 41 | return gulp.src(path.join(conf.paths.tmp, '/serve/*.html')) 42 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 43 | .pipe(assets = $.useref.assets()) 44 | .pipe($.rev()) 45 | .pipe(jsFilter) 46 | .pipe($.sourcemaps.init()) 47 | .pipe($.ngAnnotate()) 48 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) 49 | .pipe($.sourcemaps.write('maps')) 50 | .pipe(jsFilter.restore) 51 | .pipe(cssFilter) 52 | .pipe($.sourcemaps.init()) 53 | .pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/')) 54 | .pipe($.replace('../../bower_components/font-awesome/fonts/', '../fonts/')) 55 | .pipe($.minifyCss({ processImport: false })) 56 | .pipe($.sourcemaps.write('maps')) 57 | .pipe(cssFilter.restore) 58 | .pipe(assets.restore()) 59 | .pipe($.useref()) 60 | .pipe($.revReplace()) 61 | .pipe(htmlFilter) 62 | .pipe($.minifyHtml({ 63 | empty: true, 64 | spare: true, 65 | quotes: true, 66 | conditionals: true 67 | })) 68 | .pipe(htmlFilter.restore) 69 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))) 70 | .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); 71 | }); 72 | 73 | // Only applies for fonts from bower dependencies 74 | // Custom fonts are handled by the "other" task 75 | gulp.task('fonts', function () { 76 | return gulp.src($.mainBowerFiles()) 77 | .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) 78 | .pipe($.flatten()) 79 | .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/'))); 80 | }); 81 | 82 | gulp.task('other', function () { 83 | var fileFilter = $.filter(function (file) { 84 | return file.stat.isFile(); 85 | }); 86 | 87 | return gulp.src([ 88 | path.join(conf.paths.src, '/**/*'), 89 | path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}') 90 | ]) 91 | .pipe(fileFilter) 92 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))); 93 | }); 94 | 95 | gulp.task('clean', function () { 96 | return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]); 97 | }); 98 | 99 | gulp.task('build', ['html', 'fonts', 'other']); 100 | -------------------------------------------------------------------------------- /angular/gulp/conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains the variables used in other gulp files 3 | * which defines tasks 4 | * By design, we only put there very generic config values 5 | * which are used in several places to keep good readability 6 | * of the tasks 7 | */ 8 | 9 | var gutil = require('gulp-util'); 10 | 11 | /** 12 | * The main paths of your project handle these with care 13 | */ 14 | exports.paths = { 15 | src: 'src', 16 | dist: 'dist', 17 | tmp: '.tmp', 18 | e2e: 'e2e' 19 | }; 20 | 21 | /** 22 | * Wiredep is the lib which inject bower dependencies in your project 23 | * Mainly used to inject script tags in the index.html but also used 24 | * to inject css preprocessor deps and js files in karma 25 | */ 26 | exports.wiredep = { 27 | exclude: [/\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/], 28 | directory: 'bower_components' 29 | }; 30 | 31 | /** 32 | * Common implementation for an error handler of a Gulp plugin 33 | */ 34 | exports.errorHandler = function(title) { 35 | 'use strict'; 36 | 37 | return function(err) { 38 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); 39 | this.emit('end'); 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /angular/gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver-update', $.protractor.webdriver_update); 13 | 14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 15 | 16 | function runProtractor (done) { 17 | var params = process.argv; 18 | var args = params.length > 3 ? [params[3], params[4]] : []; 19 | 20 | gulp.src(path.join(conf.paths.e2e, '/**/*.js')) 21 | .pipe($.protractor.protractor({ 22 | configFile: 'protractor.conf.js', 23 | args: args 24 | })) 25 | .on('error', function (err) { 26 | // Make sure failed tests cause gulp to exit non-zero 27 | throw err; 28 | }) 29 | .on('end', function () { 30 | // Close browser sync server 31 | browserSync.exit(); 32 | done(); 33 | }); 34 | } 35 | 36 | gulp.task('protractor', ['protractor:src']); 37 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 38 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 39 | -------------------------------------------------------------------------------- /angular/gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | var _ = require('lodash'); 11 | 12 | var browserSync = require('browser-sync'); 13 | 14 | gulp.task('inject-reload', ['inject'], function() { 15 | browserSync.reload(); 16 | }); 17 | 18 | gulp.task('inject', ['scripts', 'styles'], function () { 19 | var injectStyles = gulp.src([ 20 | path.join(conf.paths.tmp, '/serve/app/**/*.css'), 21 | path.join('!' + conf.paths.tmp, '/serve/app/vendor.css') 22 | ], { read: false }); 23 | 24 | var injectScripts = gulp.src([ 25 | path.join(conf.paths.src, '/app/**/*.module.js'), 26 | path.join(conf.paths.src, '/app/**/*.js'), 27 | path.join('!' + conf.paths.src, '/app/**/*.spec.js'), 28 | path.join('!' + conf.paths.src, '/app/**/*.mock.js'), 29 | ]) 30 | .pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort')); 31 | 32 | var injectOptions = { 33 | ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')], 34 | addRootSlash: false 35 | }; 36 | 37 | return gulp.src(path.join(conf.paths.src, '/*.html')) 38 | .pipe($.inject(injectStyles, injectOptions)) 39 | .pipe($.inject(injectScripts, injectOptions)) 40 | .pipe(wiredep(_.extend({}, conf.wiredep))) 41 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve'))); 42 | }); 43 | -------------------------------------------------------------------------------- /angular/gulp/scripts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | 12 | gulp.task('scripts-reload', function() { 13 | return buildScripts() 14 | .pipe(browserSync.stream()); 15 | }); 16 | 17 | gulp.task('scripts', function() { 18 | return buildScripts(); 19 | }); 20 | 21 | function buildScripts() { 22 | return gulp.src(path.join(conf.paths.src, '/app/**/*.js')) 23 | .pipe($.eslint()) 24 | .pipe($.eslint.format()) 25 | .pipe($.size()) 26 | }; 27 | -------------------------------------------------------------------------------- /angular/gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | var browserSyncSpa = require('browser-sync-spa'); 9 | 10 | var util = require('util'); 11 | 12 | var proxyMiddleware = require('http-proxy-middleware'); 13 | 14 | function browserSyncInit(baseDir, browser) { 15 | browser = browser === undefined ? 'default' : browser; 16 | 17 | var routes = null; 18 | if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) { 19 | routes = { 20 | '/bower_components': 'bower_components' 21 | }; 22 | } 23 | 24 | var server = { 25 | baseDir: baseDir, 26 | routes: routes 27 | }; 28 | 29 | /* 30 | * You can add a proxy to your backend by uncommenting the line below. 31 | * You just have to configure a context which will we redirected and the target url. 32 | * Example: $http.get('/users') requests will be automatically proxified. 33 | * 34 | * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.9.0/README.md 35 | */ 36 | // server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', changeOrigin: true}); 37 | 38 | browserSync.instance = browserSync.init({ 39 | startPath: '/', 40 | server: server, 41 | browser: browser 42 | }); 43 | } 44 | 45 | browserSync.use(browserSyncSpa({ 46 | selector: '[ng-app]'// Only needed for angular apps 47 | })); 48 | 49 | gulp.task('serve', ['watch'], function () { 50 | browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]); 51 | }); 52 | 53 | gulp.task('serve:dist', ['build'], function () { 54 | browserSyncInit(conf.paths.dist); 55 | }); 56 | 57 | gulp.task('serve:e2e', ['inject'], function () { 58 | browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []); 59 | }); 60 | 61 | gulp.task('serve:e2e-dist', ['build'], function () { 62 | browserSyncInit(conf.paths.dist, []); 63 | }); 64 | -------------------------------------------------------------------------------- /angular/gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | var wiredep = require('wiredep').stream; 12 | var _ = require('lodash'); 13 | 14 | gulp.task('styles-reload', ['styles'], function() { 15 | return buildStyles() 16 | .pipe(browserSync.stream()); 17 | }); 18 | 19 | gulp.task('styles', function() { 20 | return buildStyles(); 21 | }); 22 | 23 | var buildStyles = function() { 24 | var sassOptions = { 25 | style: 'expanded' 26 | }; 27 | 28 | var injectFiles = gulp.src([ 29 | path.join(conf.paths.src, '/app/**/*.scss'), 30 | path.join('!' + conf.paths.src, '/app/index.scss') 31 | ], { read: false }); 32 | 33 | var injectOptions = { 34 | transform: function(filePath) { 35 | filePath = filePath.replace(conf.paths.src + '/app/', ''); 36 | return '@import "' + filePath + '";'; 37 | }, 38 | starttag: '// injector', 39 | endtag: '// endinjector', 40 | addRootSlash: false 41 | }; 42 | 43 | 44 | return gulp.src([ 45 | path.join(conf.paths.src, '/app/index.scss') 46 | ]) 47 | .pipe($.inject(injectFiles, injectOptions)) 48 | .pipe(wiredep(_.extend({}, conf.wiredep))) 49 | .pipe($.sourcemaps.init()) 50 | .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) 51 | .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) 52 | .pipe($.sourcemaps.write()) 53 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 54 | }; 55 | -------------------------------------------------------------------------------- /angular/gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var karma = require('karma'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | var pathSrcJs = [ 14 | path.join(conf.paths.src, '/**/!(*.spec).js') 15 | ]; 16 | 17 | function runTests (singleRun, done) { 18 | var reporters = ['progress']; 19 | var preprocessors = {}; 20 | 21 | pathSrcHtml.forEach(function(path) { 22 | preprocessors[path] = ['ng-html2js']; 23 | }); 24 | 25 | if (singleRun) { 26 | pathSrcJs.forEach(function(path) { 27 | preprocessors[path] = ['coverage']; 28 | }); 29 | reporters.push('coverage') 30 | } 31 | 32 | var localConfig = { 33 | configFile: path.join(__dirname, '/../karma.conf.js'), 34 | singleRun: singleRun, 35 | autoWatch: !singleRun, 36 | reporters: reporters, 37 | preprocessors: preprocessors 38 | }; 39 | 40 | var server = new karma.Server(localConfig, function(failCount) { 41 | done(failCount ? new Error("Failed " + failCount + " tests.") : null); 42 | }) 43 | server.start(); 44 | } 45 | 46 | gulp.task('test', ['scripts'], function(done) { 47 | runTests(true, done); 48 | }); 49 | 50 | gulp.task('test:auto', ['watch'], function(done) { 51 | runTests(false, done); 52 | }); 53 | -------------------------------------------------------------------------------- /angular/gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | function isOnlyChange(event) { 10 | return event.type === 'changed'; 11 | } 12 | 13 | gulp.task('watch', ['inject'], function () { 14 | 15 | gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']); 16 | 17 | gulp.watch([ 18 | path.join(conf.paths.src, '/app/**/*.css'), 19 | path.join(conf.paths.src, '/app/**/*.scss') 20 | ], function(event) { 21 | if(isOnlyChange(event)) { 22 | gulp.start('styles-reload'); 23 | } else { 24 | gulp.start('inject-reload'); 25 | } 26 | }); 27 | 28 | gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) { 29 | if(isOnlyChange(event)) { 30 | gulp.start('scripts-reload'); 31 | } else { 32 | gulp.start('inject-reload'); 33 | } 34 | }); 35 | 36 | gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) { 37 | browserSync.reload(event.path); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /angular/gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your gulpfile! 3 | * The gulp tasks are splitted in several files in the gulp directory 4 | * because putting all here was really too long 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var gulp = require('gulp'); 10 | var wrench = require('wrench'); 11 | 12 | /** 13 | * This will load all js or coffee files in the gulp directory 14 | * in order to load all gulp tasks 15 | */ 16 | wrench.readdirSyncRecursive('./gulp').filter(function(file) { 17 | return (/\.(js|coffee)$/i).test(file); 18 | }).map(function(file) { 19 | require('./gulp/' + file); 20 | }); 21 | 22 | 23 | /** 24 | * Default task clean temporaries directories and launch the 25 | * main optimization build task 26 | */ 27 | gulp.task('default', ['clean'], function () { 28 | gulp.start('build'); 29 | }); 30 | -------------------------------------------------------------------------------- /angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var conf = require('./gulp/conf'); 5 | 6 | var _ = require('lodash'); 7 | var wiredep = require('wiredep'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | function listFiles() { 14 | var wiredepOptions = _.extend({}, conf.wiredep, { 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | 19 | var patterns = wiredep(wiredepOptions).js 20 | .concat([ 21 | path.join(conf.paths.src, '/app/**/*.module.js'), 22 | path.join(conf.paths.src, '/app/**/*.js'), 23 | path.join(conf.paths.src, '/**/*.spec.js'), 24 | path.join(conf.paths.src, '/**/*.mock.js'), 25 | ]) 26 | .concat(pathSrcHtml); 27 | 28 | var files = patterns.map(function(pattern) { 29 | return { 30 | pattern: pattern 31 | }; 32 | }); 33 | files.push({ 34 | pattern: path.join(conf.paths.src, '/assets/**/*'), 35 | included: false, 36 | served: true, 37 | watched: false 38 | }); 39 | return files; 40 | } 41 | 42 | module.exports = function(config) { 43 | 44 | var configuration = { 45 | files: listFiles(), 46 | 47 | singleRun: true, 48 | 49 | autoWatch: false, 50 | 51 | ngHtml2JsPreprocessor: { 52 | stripPrefix: conf.paths.src + '/', 53 | moduleName: 'myIot' 54 | }, 55 | 56 | logLevel: 'WARN', 57 | 58 | frameworks: ['jasmine', 'angular-filesort'], 59 | 60 | angularFilesort: { 61 | whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')] 62 | }, 63 | 64 | browsers : ['PhantomJS'], 65 | 66 | plugins : [ 67 | 'karma-phantomjs-launcher', 68 | 'karma-angular-filesort', 69 | 'karma-coverage', 70 | 'karma-jasmine', 71 | 'karma-ng-html2js-preprocessor' 72 | ], 73 | 74 | coverageReporter: { 75 | type : 'html', 76 | dir : 'coverage/' 77 | }, 78 | 79 | reporters: ['progress'], 80 | 81 | proxies: { 82 | '/assets/': path.join('/base/', conf.paths.src, '/assets/') 83 | } 84 | }; 85 | 86 | // This is the default preprocessors configuration for a usage with Karma cli 87 | // The coverage preprocessor is added in gulp/unit-test.js only for single tests 88 | // It was not possible to do it there because karma doesn't let us now if we are 89 | // running a single test or not 90 | configuration.preprocessors = {}; 91 | pathSrcHtml.forEach(function(path) { 92 | configuration.preprocessors[path] = ['ng-html2js']; 93 | }); 94 | 95 | // This block is needed to execute Chrome on Travis 96 | // If you ever plan to use Chrome and Travis, you can keep it 97 | // If not, you can safely remove it 98 | // https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076 99 | if(configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) { 100 | configuration.customLaunchers = { 101 | 'chrome-travis-ci': { 102 | base: 'Chrome', 103 | flags: ['--no-sandbox'] 104 | } 105 | }; 106 | configuration.browsers = ['chrome-travis-ci']; 107 | } 108 | 109 | config.set(configuration); 110 | }; 111 | -------------------------------------------------------------------------------- /angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "scripts": { 6 | "test": "gulp test" 7 | }, 8 | "devDependencies": { 9 | "estraverse": "~4.1.0", 10 | "gulp": "~3.9.0", 11 | "gulp-autoprefixer": "~3.0.2", 12 | "gulp-angular-templatecache": "~1.8.0", 13 | "del": "~2.0.2", 14 | "lodash": "~3.10.1", 15 | "gulp-minify-css": "~1.2.1", 16 | "gulp-filter": "~3.0.1", 17 | "gulp-flatten": "~0.2.0", 18 | "gulp-eslint": "~1.0.0", 19 | "eslint-plugin-angular": "~0.12.0", 20 | "gulp-load-plugins": "~0.10.0", 21 | "gulp-size": "~2.0.0", 22 | "gulp-uglify": "~1.4.1", 23 | "gulp-useref": "~1.3.0", 24 | "gulp-util": "~3.0.6", 25 | "gulp-ng-annotate": "~1.1.0", 26 | "gulp-replace": "~0.5.4", 27 | "gulp-rename": "~1.2.2", 28 | "gulp-rev": "~6.0.1", 29 | "gulp-rev-replace": "~0.4.2", 30 | "gulp-minify-html": "~1.0.4", 31 | "gulp-inject": "~3.0.0", 32 | "gulp-protractor": "~1.0.0", 33 | "gulp-sourcemaps": "~1.6.0", 34 | "gulp-sass": "~2.0.4", 35 | "gulp-angular-filesort": "~1.1.1", 36 | "main-bower-files": "~2.9.0", 37 | "wiredep": "~2.2.2", 38 | "karma": "~0.13.10", 39 | "karma-jasmine": "~0.3.6", 40 | "karma-phantomjs-launcher": "~0.2.1", 41 | "phantomjs": "~1.9.18", 42 | "karma-angular-filesort": "~1.0.0", 43 | "karma-coverage": "~0.5.2", 44 | "karma-ng-html2js-preprocessor": "~0.2.0", 45 | "browser-sync": "~2.9.11", 46 | "browser-sync-spa": "~1.0.3", 47 | "http-proxy-middleware": "~0.9.0", 48 | "chalk": "~1.1.1", 49 | "uglify-save-license": "~0.4.1", 50 | "wrench": "~1.5.8" 51 | }, 52 | "engines": { 53 | "node": ">=0.10.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /angular/protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | baseUrl: 'http://localhost:3000', 17 | 18 | // Spec patterns are relative to the current working directory when 19 | // protractor is called. 20 | specs: [paths.e2e + '/**/*.js'], 21 | 22 | // Options to be passed to Jasmine-node. 23 | jasmineNodeOpts: { 24 | showColors: true, 25 | defaultTimeoutInterval: 30000 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /angular/src/Cyborg.scss: -------------------------------------------------------------------------------- 1 | $bootstrap-sass-asset-helper: false !default; 2 | // Cyborg 3.3.6 3 | // Variables 4 | // -------------------------------------------------- 5 | 6 | 7 | //== Colors 8 | // 9 | //## Gray and brand colors for use across Bootstrap. 10 | 11 | $gray-base: #000 !default; 12 | $gray-darker: #222 !default; // #222 13 | $gray-dark: #282828 !default; // #333 14 | $gray: #555 !default; // #555 15 | $gray-light: #888 !default; // #999 16 | $gray-lighter: #ADAFAE !default; // #eee 17 | 18 | $brand-primary: #2A9FD6 !default; 19 | $brand-success: #77B300 !default; 20 | $brand-info: #9933CC !default; 21 | $brand-warning: #FF8800 !default; 22 | $brand-danger: #CC0000 !default; 23 | 24 | 25 | //== Scaffolding 26 | // 27 | //## Settings for some of the most global styles. 28 | 29 | //** Background color for `
`. 30 | $body-bg: #060606 !default; 31 | //** Global text color on ``. 32 | $text-color: $gray-light !default; 33 | 34 | //** Global textual link color. 35 | $link-color: $brand-primary !default; 36 | //** Link hover color set via `darken()` function. 37 | $link-hover-color: $link-color !default; 38 | //** Link hover decoration. 39 | $link-hover-decoration: underline !default; 40 | 41 | 42 | //== Typography 43 | // 44 | //## Font, line-height, and color for body text, headings, and more. 45 | 46 | $font-family-sans-serif: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif !default; 47 | $font-family-serif: Georgia, "Times New Roman", Times, serif !default; 48 | //** Default monospace fonts for ``, ``, and ``.
49 | $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default;
50 | $font-family-base: $font-family-sans-serif !default;
51 |
52 | $font-size-base: 14px !default;
53 | $font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px
54 | $font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px
55 |
56 | $font-size-h1: 56px !default;
57 | $font-size-h2: 45px !default;
58 | $font-size-h3: 34px !default;
59 | $font-size-h4: 24px !default;
60 | $font-size-h5: 20px !default;
61 | $font-size-h6: 16px !default;
62 |
63 | //** Unit-less `line-height` for use in components like buttons.
64 | $line-height-base: 1.428571429 !default; // 20/14
65 | //** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
66 | $line-height-computed: floor(($font-size-base * $line-height-base)) !default; // ~20px
67 |
68 | //** By default, this inherits from the ``.
69 | $headings-font-family: $font-family-base !default;
70 | $headings-font-weight: 500 !default;
71 | $headings-line-height: 1.1 !default;
72 | $headings-color: #fff !default;
73 |
74 |
75 | //== Iconography
76 | //
77 | //## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
78 |
79 | //** Load fonts from this directory.
80 | $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
81 | //** File name for all font files.
82 | $icon-font-name: "glyphicons-halflings-regular" !default;
83 | //** Element ID within SVG icon file.
84 | $icon-font-svg-id: "glyphicons_halflingsregular" !default;
85 |
86 |
87 | //== Components
88 | //
89 | //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
90 |
91 | $padding-base-vertical: 8px !default;
92 | $padding-base-horizontal: 12px !default;
93 |
94 | $padding-large-vertical: 14px !default;
95 | $padding-large-horizontal: 16px !default;
96 |
97 | $padding-small-vertical: 5px !default;
98 | $padding-small-horizontal: 10px !default;
99 |
100 | $padding-xs-vertical: 1px !default;
101 | $padding-xs-horizontal: 5px !default;
102 |
103 | $line-height-large: 1.3333333 !default; // extra decimals for Win 8.1 Chrome
104 | $line-height-small: 1.5 !default;
105 |
106 | $border-radius-base: 4px !default;
107 | $border-radius-large: 6px !default;
108 | $border-radius-small: 3px !default;
109 |
110 | //** Global color for active items (e.g., navs or dropdowns).
111 | $component-active-color: #fff !default;
112 | //** Global background color for active items (e.g., navs or dropdowns).
113 | $component-active-bg: $brand-primary !default;
114 |
115 | //** Width of the `border` for generating carets that indicator dropdowns.
116 | $caret-width-base: 4px !default;
117 | //** Carets increase slightly in size for larger components.
118 | $caret-width-large: 5px !default;
119 |
120 |
121 | //== Tables
122 | //
123 | //## Customizes the `.table` component with basic values, each used across all table variations.
124 |
125 | //** Padding for ``s and ` `s.
126 | $table-cell-padding: 8px !default;
127 | //** Padding for cells in `.table-condensed`.
128 | $table-condensed-cell-padding: 5px !default;
129 |
130 | //** Default background color used for all tables.
131 | $table-bg: darken($gray-darker, 4%) !default;
132 | //** Background color used for `.table-striped`.
133 | $table-bg-accent: darken($table-bg, 6%) !default;
134 | //** Background color used for `.table-hover`.
135 | $table-bg-hover: $gray-dark !default;
136 | $table-bg-active: $table-bg-hover !default;
137 |
138 | //** Border color for table and cell borders.
139 | $table-border-color: $gray-dark !default;
140 |
141 |
142 | //== Buttons
143 | //
144 | //## For each of Bootstrap's buttons, define text, background and border color.
145 |
146 | $btn-font-weight: normal !default;
147 |
148 | $btn-default-color: #fff !default;
149 | $btn-default-bg: lighten($gray-dark, 10%) !default;
150 | $btn-default-border: $btn-default-bg !default;
151 |
152 | $btn-primary-color: $btn-default-color !default;
153 | $btn-primary-bg: $brand-primary !default;
154 | $btn-primary-border: $btn-primary-bg !default;
155 |
156 | $btn-success-color: $btn-default-color !default;
157 | $btn-success-bg: $brand-success !default;
158 | $btn-success-border: $btn-success-bg !default;
159 |
160 | $btn-info-color: $btn-default-color !default;
161 | $btn-info-bg: $brand-info !default;
162 | $btn-info-border: $btn-info-bg !default;
163 |
164 | $btn-warning-color: $btn-default-color !default;
165 | $btn-warning-bg: $brand-warning !default;
166 | $btn-warning-border: $btn-warning-bg !default;
167 |
168 | $btn-danger-color: $btn-default-color !default;
169 | $btn-danger-bg: $brand-danger !default;
170 | $btn-danger-border: $btn-danger-bg !default;
171 |
172 | $btn-link-disabled-color: $gray-light !default;
173 |
174 | // Allows for customizing button radius independently from global border radius
175 | $btn-border-radius-base: $border-radius-base !default;
176 | $btn-border-radius-large: $border-radius-large !default;
177 | $btn-border-radius-small: $border-radius-small !default;
178 |
179 |
180 | //== Forms
181 | //
182 | //##
183 |
184 | //** `` background color
185 | $input-bg: #fff !default;
186 | //** `` background color
187 | $input-bg-disabled: $gray-lighter !default;
188 |
189 | //** Text color for ``s
190 | $input-color: $text-color !default;
191 | //** `` border color
192 | $input-border: $gray-dark !default;
193 |
194 | // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
195 | //** Default `.form-control` border radius
196 | // This has no effect on `