0
0
mirror of https://github.com/Doodle3D/doodle3d-client.git synced 2024-11-04 19:33:22 +01:00

Compare commits

..

No commits in common. "master" and "0.10.9" have entirely different histories.

12 changed files with 53 additions and 186 deletions

9
.gitignore vendored
View File

@ -18,11 +18,18 @@ img/logo/logo_smaller.png
img/logo/logo_smaller_8bit.png img/logo/logo_smaller_8bit.png
img/logo/logo_smaller_wide_8bit.png img/logo/logo_smaller_wide_8bit.png
img/logo/logo_smallest.png img/logo/logo_smallest.png
css/_backup20131010/*
css/_backup20131011/*
d3d_btns.css d3d_btns.css
index.html.orig
js/Thermometer.js.orig
js/buttonbehaviors.js.orig
js/gcodeGenerating_v01.js.orig
js/init_layout backup20130918.js
js/main.js.orig js/main.js.orig
js/previewRendering_v02.js.orig
less/verticalshapes.css less/verticalshapes.css
less/verticalshapes_backup.css less/verticalshapes_backup.css
__settings.html __settings.html
css/_settings.css css/_settings.css
node_modules/* node_modules/*
js/main.js.out

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
included=//*.js

View File

@ -10,32 +10,6 @@ module.exports = function(grunt) {
'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n', ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
gitinfo: {
options: {},
commands: { 'tag': ['tag', '--points-at', 'HEAD'] }
},
template: {
'add_build_info': {
options: {
data: function() {
grunt.task.requires('gitinfo');
var gi = grunt.config('gitinfo');
var lbc = gi.local.branch.current;
var tags = (gi.tag == '') ? 'no_tag' : gi.tag;
tags = tags.split('\n').join(',');
var commitMsg = lbc.lastCommitMessage.slice(1, -1).split('\n')[0].replace(/"/g, '\\\"');
var buildInfo = lbc.shortSHA + "/" + lbc.name + "/" + tags +
" (" + lbc.lastCommitTime.slice(1, -1) + "; \'" + commitMsg + "'";
return { 'build_info': buildInfo };
}
},
files: {
'js/main.js.out': ['js/main.js']
}
}
},
concat: { concat: {
options: { options: {
// separator: ';' // separator: ';'
@ -48,8 +22,7 @@ module.exports = function(grunt) {
'js/*.js', 'js/*.js',
// make sure we put main.js last // make sure we put main.js last
'!js/main.js', '!js/main.js',
'js/main.js.out' 'js/main.js', ],
],
dest: 'www/js/<%= pkg.name %>.js' dest: 'www/js/<%= pkg.name %>.js'
} }
}, },
@ -156,8 +129,6 @@ module.exports = function(grunt) {
}); });
// These plugins provide necessary tasks. // These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-gitinfo');
grunt.loadNpmTasks('grunt-template');
grunt.loadNpmTasks('grunt-contrib-less'); grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-uglify');
@ -168,8 +139,6 @@ module.exports = function(grunt) {
// Default task. // Default task.
grunt.registerTask('default', [ grunt.registerTask('default', [
'gitinfo',
'template',
'less', 'less',
'autoprefixer', 'autoprefixer',
'cssmin', 'cssmin',

View File

@ -34,7 +34,6 @@ endef
define Build/Prepare define Build/Prepare
mkdir -p $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR)
$(CP) js $(PKG_BUILD_DIR)/
$(CP) less $(PKG_BUILD_DIR)/ $(CP) less $(PKG_BUILD_DIR)/
$(CP) www $(PKG_BUILD_DIR)/ $(CP) www $(PKG_BUILD_DIR)/
$(CP) Gruntfile.js $(PKG_BUILD_DIR)/ $(CP) Gruntfile.js $(PKG_BUILD_DIR)/
@ -44,16 +43,12 @@ define Build/Prepare
endef endef
define Build/Compile define Build/Compile
# We're running grunt in the shared folder, so
# grunt can access git info
npm install npm install
ifeq ($(CONFIG_DOODLE3D_CLIENT_MINIFY_JS),y) ifeq ($(CONFIG_DOODLE3D_CLIENT_MINIFY_JS),y)
grunt gitinfo template less autoprefixer cssmin concat uglify grunt less autoprefixer cssmin concat uglify
else else
grunt gitinfo template less autoprefixer cssmin concat grunt less autoprefixer cssmin concat
endif endif
# Copy compiled files to build dir
$(CP) www $(PKG_BUILD_DIR)/
endef endef
define Package/doodle3d-client/install define Package/doodle3d-client/install

View File

@ -25,7 +25,7 @@ function Message() {
this.$element = $element; this.$element = $element;
} }
this.set = function(contents,mode,autoHide,disableEffect) { this.set = function(contents,mode,autoHide,disableEffect) {
//console.log("Message:set: ",contents,mode,autoHide,disableEffect); console.log("Message:set: ",contents,mode,autoHide,disableEffect);
if(disableEffect) { if(disableEffect) {
self.fill(contents,mode,autoHide) self.fill(contents,mode,autoHide)
} else{ } else{

View File

@ -19,7 +19,6 @@ function setPrintprogress(val) {
//*/ //*/
function Printer() { function Printer() {
/* CONSTANTS */
Printer.WIFIBOX_DISCONNECTED_STATE = "wifibox disconnected"; Printer.WIFIBOX_DISCONNECTED_STATE = "wifibox disconnected";
Printer.UNKNOWN_STATE = "unknown"; // happens when a printer is connection but there isn't communication yet Printer.UNKNOWN_STATE = "unknown"; // happens when a printer is connection but there isn't communication yet
@ -33,29 +32,11 @@ function Printer() {
Printer.ON_BEFORE_UNLOAD_MESSAGE = "You're doodle is still being sent to the printer, leaving will result in a incomplete 3D print"; Printer.ON_BEFORE_UNLOAD_MESSAGE = "You're doodle is still being sent to the printer, leaving will result in a incomplete 3D print";
//after buffer full message has been received, wait until the buffer load is below this ratio before sending new data
Printer.GCODE_BUFFER_WAIT_LOAD_RATIO = 0.75;
Printer.BUFFER_SPACE_WAIT_TIMEOUT = 30000; // how often to recheck buffer load
//time to wait when wifibox connection is lost while printing
Printer.DISCONNECTED_RETRY_DELAY = 5000;
Printer.MAX_LINES_PER_POST = 500; // max amount of gcode lines per post (limited because WiFi box can't handle too much)
Printer.MAX_GCODE_SIZE = 10; // max size of gcode in MB's (estimation)
// Events
Printer.UPDATE = "update";
/* MEMBER VARIABLES */
this.temperature = 0; this.temperature = 0;
this.targetTemperature = 0; this.targetTemperature = 0;
this.currentLine = 0; this.currentLine = 0;
this.totalLines = 0; this.totalLines = 0;
this.bufferedLines = 0; this.bufferedLines = 0;
this.bufferSize = 0;
this.maxBufferSize = 0;
this.state = Printer.UNKNOWN_STATE; this.state = Printer.UNKNOWN_STATE;
this.hasControl = true; // whether this client has control access this.hasControl = true; // whether this client has control access
@ -66,8 +47,8 @@ function Printer() {
this.timeoutTime = 3000; this.timeoutTime = 3000;
this.sendPrintPartTimeoutTime = 5000; this.sendPrintPartTimeoutTime = 5000;
this.gcode = []; // gcode to be printed this.gcode; // gcode to be printed
this.gcodeNumChunks = 0; //number of chunks to be sent (used for sequence numbering) this.sendLength = 500; // max amount of gcode lines per post (limited because WiFi box can't handle too much)
this.retryDelay = 2000; // retry setTimout delay this.retryDelay = 2000; // retry setTimout delay
this.retrySendPrintPartDelay; // retry setTimout instance this.retrySendPrintPartDelay; // retry setTimout instance
@ -75,10 +56,12 @@ function Printer() {
this.retryStopDelay; // retry setTimout instance this.retryStopDelay; // retry setTimout instance
this.retryPreheatDelay; // retry setTimout instance this.retryPreheatDelay; // retry setTimout instance
Printer.MAX_GCODE_SIZE = 10; // max size of gcode in MB's (estimation)
this.stateOverruled = false; this.stateOverruled = false;
// Events
/* FUNCTIONS */ Printer.UPDATE = "update";
var self = this; var self = this;
@ -137,7 +120,6 @@ function Printer() {
this.sendIndex = 0; this.sendIndex = 0;
this.gcode = gcode; this.gcode = gcode;
this.gcodeNumChunks = Math.ceil(this.gcode.length / Printer.MAX_LINES_PER_POST);
//console.log(" gcode[20]: ",gcode[20]); //console.log(" gcode[20]: ",gcode[20]);
var gcodeLineSize = this.byteSize(gcode[20]); var gcodeLineSize = this.byteSize(gcode[20]);
@ -160,7 +142,7 @@ function Printer() {
//this.targetTemperature = settings["printer.temperature"]; // slight hack //this.targetTemperature = settings["printer.temperature"]; // slight hack
this.sendPrintPart(this.sendIndex, Printer.MAX_LINES_PER_POST); this.sendPrintPart(this.sendIndex, this.sendLength);
} }
this.byteSize = function(s){ this.byteSize = function(s){
@ -168,43 +150,26 @@ function Printer() {
} }
this.sendPrintPart = function(sendIndex,sendLength) { this.sendPrintPart = function(sendIndex,sendLength) {
var self = this; console.log("Printer:sendPrintPart sendIndex: " + sendIndex + "/" + this.gcode.length + ", sendLength: " + sendLength);
// Abort if stopping
// sendPrintPart can be called by delayed retry after request timeout for example
if (self.state === Printer.STOPPING_STATE) return; var sendPercentage = Math.round(sendIndex/this.gcode.length*100);
message.set("Sending doodle to printer: "+sendPercentage+"%",Message.NOTICE,false,true);
var firstOne = (sendIndex == 0)? true : false;
var start = firstOne; // start printing right away
var completed = false; var completed = false;
if (this.gcode.length < (sendIndex + sendLength)) { if (this.gcode.length < (sendIndex + sendLength)) {
console.log(" sending less than max sendLength (and last)");
sendLength = this.gcode.length - sendIndex; sendLength = this.gcode.length - sendIndex;
//lastOne = true;
completed = true; completed = true;
} }
var gcodePart = this.gcode.slice(sendIndex, sendIndex+sendLength);
var postData = { gcode: gcodePart.join("\n"), first: firstOne, start: start};
/* prepare post data */ var self = this;
var gcodePart = this.gcode.slice(sendIndex, sendIndex + sendLength);
var firstOne = (sendIndex == 0) ? true : false;
var start = firstOne; // start printing right away
var seqNum = Math.floor(sendIndex / Printer.MAX_LINES_PER_POST);
var postData = {
gcode: gcodePart.join("\n"), total_lines: this.gcode.length,
clear: firstOne, start: start,
seq_number: seqNum, seq_total: this.gcodeNumChunks
};
/* inform user what's going on */
var lessThanMaxText = completed ? " (last one, max=" + Printer.MAX_LINES_PER_POST + ")" : "";
console.log("Printer:sendPrintPart: sendIndex=" + sendIndex + "/" + this.gcode.length +
", sendLength=" + sendLength + lessThanMaxText +
", sequence numbers: " + seqNum + "/" + this.gcodeNumChunks);
var sendPercentage = Math.round(sendIndex / this.gcode.length * 100);
message.set("Sending doodle to printer: " + sendPercentage + "%", Message.NOTICE, false, true);
/* send data */
if (communicateWithWifibox) { if (communicateWithWifibox) {
$.ajax({ $.ajax({
url: this.wifiboxURL + "/printer/print", url: this.wifiboxURL + "/printer/print",
@ -213,13 +178,13 @@ function Printer() {
dataType: 'json', dataType: 'json',
timeout: this.sendPrintPartTimeoutTime, timeout: this.sendPrintPartTimeoutTime,
success: function(data){ success: function(data){
//console.log("Printer:sendPrintPart success response: ", data); console.log("Printer:sendPrintPart response: ",data);
if(data.status == "success") { if(data.status == "success") {
if (completed) { if (completed) {
console.log("Printer:sendPrintPart: gcode sending completed"); console.log("Printer:sendPrintPart:gcode sending completed");
this.gcode = []; this.gcode = [];
this.gcodeNumChunks = 0; btnStop.css("display","block"); // hack
self.removeLeaveWarning(); self.removeLeaveWarning();
message.set("Doodle has been sent to printer...",Message.INFO,true); message.set("Doodle has been sent to printer...",Message.INFO,true);
//self.targetTemperature = settings["printer.temperature"]; // slight hack //self.targetTemperature = settings["printer.temperature"]; // slight hack
@ -230,48 +195,23 @@ function Printer() {
if(self.state == Printer.PRINTING_STATE || self.state == Printer.BUFFERING_STATE) { if(self.state == Printer.PRINTING_STATE || self.state == Printer.BUFFERING_STATE) {
//console.log("Printer:sendPrintPart:sending next part"); //console.log("Printer:sendPrintPart:sending next part");
self.sendPrintPart(sendIndex + sendLength, sendLength); self.sendPrintPart(sendIndex + sendLength, sendLength);
} else if (Printer.WIFIBOX_DISCONNECTED_STATE) {
console.warn("Printer:sendPrintPart: wifibox connection lost while printing, retrying in " + (Printer.DISCONNECTED_RETRY_DELAY / 1000) + " seconds");
clearTimeout(self.retrySendPrintPartDelay);
self.retrySendPrintPartDelay = setTimeout(function() {
console.log("Printer:sendPrintPart: retrying after wifibox disconnect was detected");
self.sendPrintPart(sendIndex, sendLength);
}, Printer.DISCONNECTED_RETRY_DELAY);
}
}
} else if (data.status == "fail") {
if (data.data.status == "buffer_full") {
console.log("Printer:sendPrintPart: print server reported buffer full, pausing data transmission");
//this will wait in a setTimeout loop until enough room is available and then call sendPrintPart again.
self.waitForBufferSpace(sendIndex, sendLength);
} else if (data.data.status == "seq_num_mismatch" && data.data.seq_number == seqNum) {
console.warn("Printer:sendPrintPart: received sequence error, server is one chunk ahead. Proceeding with next chunk...");
self.sendPrintPart(sendIndex + sendLength, sendLength);
} else {
console.error("Printer:sendPrintPart: unexpected failure response for API endpoint printer/print (" +
data.data.status + ", current server seq. info: " + data.data.seq_number + "/" + data.data.seq_total + ")");
//sequence errors should not occur, except perhaps when 'stop' was clicked while still sending (https://github.com/Doodle3D/doodle3d-client/issues/226).
if (self.state != Printer.STOPPING_STATE) {
message.set("Unexpected error sending doodle to printer (" + data.data.status + "), please retry", Message.ERROR, false, true);
} }
} }
} }
// after we know the first gcode packed has bin received or failed
// after we know the first gcode part has been received or failed
// (and the driver had time to update the printer.state) // (and the driver had time to update the printer.state)
// we start checking the status again // we start checking the status again
if(sendIndex == 0) { if(sendIndex == 0) {
self.startStatusCheckInterval(); self.startStatusCheckInterval();
} }
} }
}).fail(function(jqXHr, textStatus, errorThrown) { }).fail(function() {
console.error("Printer:sendPrintPart: failed (AJAX status: '" + textStatus + "') AJAX exception (if any):", errorThrown); console.log("Printer:sendPrintPart: failed");
console.warn("Printer:sendPrintPart: retrying in " + (Printer.DISCONNECTED_RETRY_DELAY / 1000) + " seconds");
clearTimeout(self.retrySendPrintPartDelay); clearTimeout(self.retrySendPrintPartDelay);
self.retrySendPrintPartDelay = setTimeout(function() { self.retrySendPrintPartDelay = setTimeout(function() {
console.log("Printer:sendPrintPart: retrying after AJAX failure"); console.log("request printer:sendPrintPart failed retry");
self.sendPrintPart(sendIndex, sendLength) self.sendPrintPart(sendIndex, sendLength)
}, Printer.DISCONNECTED_RETRY_DELAY); },self.retryDelay); // retry after delay
// after we know the gcode packed has bin received or failed // after we know the gcode packed has bin received or failed
// (and the driver had time to update the printer.state) // (and the driver had time to update the printer.state)
@ -283,46 +223,12 @@ function Printer() {
} }
} }
/*
* Called by sendPrintPart when a buffer_full fail response is received.
* This function keeps calling itself until the GCodeBuffer's load ratio
* drops below a predefined value and then calls sendPrintPart again.
*/
this.waitForBufferSpace = function(sendIndex,sendLength) {
var fillRatio = this.bufferSize / this.maxBufferSize;
var self = this;
//console.log("buffer fill state: " + self.bufferSize + "/" + self.maxBufferSize + " (" + fillPercent + "%)");
if (fillRatio >= Printer.GCODE_BUFFER_WAIT_LOAD_RATIO) {
var fillPercent = (fillRatio * 100).toFixed(2);
console.log("Printer:waitForBufferSpace: waiting until gcode buffer load ratio is below " +
(Printer.GCODE_BUFFER_WAIT_LOAD_RATIO * 100) + "% (current: " + fillPercent + "% of " +
(self.maxBufferSize / 1024) + "KiB)");
self.waitForBufferSpaceDelay = setTimeout(function() { self.waitForBufferSpace(sendIndex, sendLength); }, Printer.BUFFER_SPACE_WAIT_TIMEOUT);
} else {
if(self.state == Printer.PRINTING_STATE || self.state == Printer.BUFFERING_STATE) {
console.log("Printer:waitForBufferSpace: load ratio dropped below " + (Printer.GCODE_BUFFER_WAIT_LOAD_RATIO * 100) + "%, calling sendPrintPart...");
self.sendPrintPart(sendIndex, sendLength);
} else {
console.log("Printer:waitForBufferSpace: load ratio dropped far enough but printer state is not printing or buffering anymore, not resuming.");
}
}
}
this.stop = function() { this.stop = function() {
console.log("Printer:stop"); console.log("Printer:stop");
var self = this;
if (self.retrySendPrintPartDelay !== undefined) {
clearTimeout(self.retrySendPrintPartDelay);
}
if (self.waitForBufferSpaceDelay !== undefined) {
clearTimeout(self.waitForBufferSpaceDelay);
}
endCode = generateEndCode(); endCode = generateEndCode();
console.log(" endCode: ",endCode); console.log(" endCode: ",endCode);
var postData = { gcode: endCode.join("\n")}; var postData = { gcode: endCode.join("\n")};
var self = this;
if (communicateWithWifibox) { if (communicateWithWifibox) {
$.ajax({ $.ajax({
url: this.wifiboxURL + "/printer/stop", url: this.wifiboxURL + "/printer/stop",
@ -419,9 +325,7 @@ function Printer() {
// progress // progress
self.currentLine = data.current_line; self.currentLine = data.current_line;
self.totalLines = data.total_lines; self.totalLines = data.total_lines;
self.bufferedLines = data.buffered_lines; self.bufferedLines = data.buffered_lines
self.bufferSize = data.buffer_size;
self.maxBufferSize = data.max_buffer_size;
// access // access
self.hasControl = data.has_control; self.hasControl = data.has_control;

View File

@ -232,6 +232,8 @@ function print(e) {
//setState(Printer.BUFFERING_STATE,printer.hasControl); //setState(Printer.BUFFERING_STATE,printer.hasControl);
printer.overruleState(Printer.BUFFERING_STATE); printer.overruleState(Printer.BUFFERING_STATE);
btnStop.css("display","none"); // hack
// we put the gcode generation in a little delay // we put the gcode generation in a little delay
// so that for example the print button is disabled right away // so that for example the print button is disabled right away
clearTimeout(gcodeGenerateDelayer); clearTimeout(gcodeGenerateDelayer);
@ -356,7 +358,7 @@ function setState(newState,newHasControl) {
prevState = state; prevState = state;
console.log("setState: " + prevState + " > " + newState + " ( " + newHasControl + ")"); console.log("setState: ",prevState," > ",newState," ( ",newHasControl,")");
setDebugText("State: "+newState); setDebugText("State: "+newState);
// print button // print button

View File

@ -34,8 +34,7 @@ var POPUP_SHOW_DURATION = 175;
var BUTTON_GROUP_SHOW_DURATION = 80; var BUTTON_GROUP_SHOW_DURATION = 80;
$(function() { $(function() {
console.log("Doodle3D client ready"); console.log("ready");
console.log("Build information - <%= build_info %>)");
if (getURLParameter("d") != "null") debugMode = (getURLParameter("d") == "1"); if (getURLParameter("d") != "null") debugMode = (getURLParameter("d") == "1");
if (getURLParameter("p") != "null") sendPrintCommands = (getURLParameter("p") == "1"); if (getURLParameter("p") != "null") sendPrintCommands = (getURLParameter("p") == "1");

View File

@ -204,7 +204,7 @@ function UpdatePanel() {
this.setState = function(newState,refresh) { this.setState = function(newState,refresh) {
//console.log("UpdatePanel:setState"); //console.log("UpdatePanel:setState");
if(!refresh && this.state == newState) return; if(!refresh && this.state == newState) return;
console.log("UpdatePanel:setState: " + this.state + " > " + newState + "(" + this.stateText + ") (in Access Point Mode: " + _inAccessPointMode + ") (newestVersion: " + self.newestVersion + ") (refresh: " + refresh + ")"); console.log("UpdatePanel:setState: ",this.state," > ",newState,"(",this.stateText,") (in Access Point Mode: ",_inAccessPointMode,") (newestVersion: ",self.newestVersion,") (refresh: ",refresh,")");
this.state = newState; this.state = newState;
// should personal sketches and settings be retained over update? // should personal sketches and settings be retained over update?

View File

@ -41,7 +41,7 @@ function setSketchModified(_isModified) {
} }
function updateSketchButtonStates() { function updateSketchButtonStates() {
console.log('sketch: isModified: ' + isModified + ', curSketch: ' + curSketch + ', sketches.length: ' + sketches.length); console.log('sketch: isModified',isModified,'curSketch',curSketch,'sketches.length',sketches.length);
if (isModified) { if (isModified) {
btnSave.enable(); btnSave.enable();
@ -72,7 +72,7 @@ function loadSketch(_curSketch) {
var id = sketches[curSketch]; var id = sketches[curSketch];
console.log('sketch: loadSketch curSketch:' + curSketch + ', id: ' + id); console.log('sketch: loadSketch curSketch',curSketch,'id',id);
$.get(wifiboxURL + "/sketch", {id:id}, function(response) { $.get(wifiboxURL + "/sketch", {id:id}, function(response) {
if (response.status=='success') { if (response.status=='success') {

View File

@ -1,10 +1,8 @@
local M = { local M = {
BASE_PATH = 'js', BASE_PATH = 'js_src',
EXCLUDE_FILES = {}, EXCLUDE_FILES = {},
PROCESS_FILES = { PROCESS_FILES = {
['js/[^/]*%.js'] = 'cstyle', ['js_src/[^/]*%.js'] = 'cstyle'
['js/api/[^/]*%.js'] = 'cstyle',
['js/settings/[^/]*%.js'] = 'cstyle'
}, },
IGNORE_GIT_CHANGED = false IGNORE_GIT_CHANGED = false
} }

View File

@ -9,7 +9,7 @@
"author": "Peter Uithoven, Adriaan Wormgoor, Rick Companje, Wouter Reckman", "author": "Peter Uithoven, Adriaan Wormgoor, Rick Companje, Wouter Reckman",
"readmeFilename": "README.md", "readmeFilename": "README.md",
"devDependencies": { "devDependencies": {
"grunt": "~0.4.5", "grunt": "~0.4.1",
"grunt-cli": "~0.1.9", "grunt-cli": "~0.1.9",
"grunt-contrib-less": "~0.7.0", "grunt-contrib-less": "~0.7.0",
"grunt-contrib-watch": "~0.5.3", "grunt-contrib-watch": "~0.5.3",
@ -17,11 +17,6 @@
"grunt-contrib-jshint": "~0.6.4", "grunt-contrib-jshint": "~0.6.4",
"grunt-autoprefixer": "~0.4.0", "grunt-autoprefixer": "~0.4.0",
"grunt-contrib-cssmin": "~0.6.2", "grunt-contrib-cssmin": "~0.6.2",
"grunt-contrib-concat": "~0.3.0", "grunt-contrib-concat": "~0.3.0"
"grunt-gitinfo": "~0.1.7",
"grunt-template": "~0.2.3"
},
"scripts": {
"start": "grunt"
} }
} }