Merge branch 'develop'

This commit is contained in:
Iuri Matias 2015-07-15 08:09:55 -04:00
commit 8bc4c115fc
32 changed files with 438 additions and 243 deletions

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 iuri matias
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -138,6 +138,39 @@ If you are using multiple contracts, you can pass a reference to another contrac
... ...
``` ```
You can now deploy many instances of the same contract. e.g
```Yaml
# config/contracts.yml
development:
Currency:
args:
- 100
Usd:
instanceOf: Currency
args:
- "initial string"
MyCoin:
instanceOf: Currency
args:
- $SimpleStorage
...
```
Contracts addresses can be defined, If an address is defined the contract wouldn't be deployed but its defined address will be used instead.
```Yaml
development:
UserStorage:
address: 0x123456
UserManagement:
args:
- $UserStorage
...
```
Tests Tests
====== ======

View File

@ -14,8 +14,18 @@ var run = function(cmd) {
} }
} }
var deploy = fnction(embarkConfig) {
contractFiles = grunt.file.expand(embarkConfig.contracts);
destFile = embarkConfig.output
Embark.init()
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig)
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig)
abi = Embark.deployContracts(env, contractFiles, destFile)
grunt.file.write(destFile, abi);
}
program program
.version('0.5.0') .version('0.6.0')
program.command('new [name]').description('New application').action(function(name) { program.command('new [name]').description('New application').action(function(name) {
if (name === undefined) { if (name === undefined) {
@ -39,43 +49,87 @@ program.command('deploy [env]').description('deploy contracts').action(function(
run("grunt deploy_contracts:" + env); run("grunt deploy_contracts:" + env);
} }
else { else {
contractFiles = grunt.file.expand(embarkConfig.contracts); deploy();
destFile = embarkConfig.output
Embark.init()
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig)
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig)
abi = Embark.deployContracts(env, contractFiles, destFile)
grunt.file.write(destFile, abi);
} }
}); });
program.command('build [env]').description('build dapp').action(function(env_) { program.command('build [env]').description('build dapp').action(function(env_) {
var env = env_ || 'development'; var env = env_ || 'development';
var embarkConfig = readYaml.sync("./embark.yml");
if (embarkConfig.type === "grunt") {
run("grunt clean"); run("grunt clean");
run("grunt deploy_contracts:" + env); run("grunt deploy_contracts:" + env);
run('grunt build:' + env); run('grunt build:' + env);
}
else if (embarkConfig.type === "meteor") {
deploy();
run("meteor-build-client ./build -p ''");
}
}); });
program.command('ipfs [env]').description('build dapp and make it available in ipfs').action(function(env_) { program.command('ipfs [env]').description('build dapp and make it available in ipfs').action(function(env_) {
var env = env_ || 'development'; var env = env_ || 'development';
var embarkConfig = readYaml.sync("./embark.yml");
if (embarkConfig.type === "grunt") {
run("grunt clean") run("grunt clean")
run("grunt deploy_contracts:" + env) run("grunt deploy_contracts:" + env)
run('grunt build:' + env) run('grunt build:' + env)
run('grunt ipfs:' + env) run('grunt ipfs:' + env)
}
else if (embarkConfig.type === "meteor") {
deploy();
run("meteor-build-client ./build -p ''");
Embark.release.ipfs("build/")
}
else {
console.log("command not available in manual mode yet");
}
}); });
program.command('run [env]').description('run dapp').action(function(env_) { program.command('run [env]').description('run dapp').action(function(env_) {
var env = env_ || 'development'; var env = env_ || 'development';
var embarkConfig = readYaml.sync("./embark.yml");
if (embarkConfig.type === "grunt") {
run('grunt deploy:' + env); run('grunt deploy:' + env);
}
else {
console.log("command not available in meteor or manual mode yet");
console.log("try instead embark run");
}
}); });
program.command('spec').description('run specs').action(function() { program.command('spec').description('run specs').action(function() {
var embarkConfig = readYaml.sync("./embark.yml");
if (embarkConfig.type === "grunt") {
run('jasmine'); run('jasmine');
}
else {
console.log("command not available in meteor or manual mode yet");
console.log("note: you can use embark tests with any framework");
}
}); });
program.command('blockchain [env]').description('run blockchain').action(function(env_) { program.command('blockchain [env]').description('run blockchain').action(function(env_) {
var env = env_ || 'development'; var env = env_ || 'development';
var embarkConfig = readYaml.sync("./embark.yml");
if (embarkConfig.type === "grunt") {
run('grunt blockchain:' + env); run('grunt blockchain:' + env);
}
else {
Embark.init()
Embark.blockchainConfig.loadConfigFile(embarkConfig.blockchainConfig)
Embark.contractsConfig.loadConfigFile(embarkConfig.contractsConfig)
//TODO: better with --exec, but need to fix console bug first
wrench.copyDirSyncRecursive(__dirname + "/../js", "/tmp", {forceDelete: true});
Embark.startBlockchain(env, true);
}
}); });
program.command('demo').description('create a working dapp with a SimpleStorage contract').action(function() { program.command('demo').description('create a working dapp with a SimpleStorage contract').action(function() {
@ -93,6 +147,14 @@ program.command('demo').description('create a working dapp with a SimpleStorage
console.log('\n\ninit complete'); console.log('\n\ninit complete');
}); });
program.command('meteor_demo').description('create a working meteor dapp with a SimpleStorage contract').action(function() {
var boilerPath = path.join(__dirname + '/../demo_meteor');
var targetDir = "./embark_demo";
wrench.copyDirSyncRecursive(boilerPath, targetDir);
console.log('\n\ninit complete');
});
program.parse(process.argv) program.parse(process.argv)
if (!process.argv.slice(2).length) { if (!process.argv.slice(2).length) {

View File

@ -1,10 +1,12 @@
module.exports = (grunt) -> module.exports = (grunt) ->
grunt.loadNpmTasks "embark-framework" grunt.loadNpmTasks "grunt-embark"
grunt.initConfig( grunt.initConfig(
@initEmbarkConfig(
files: files:
web3:
"node_modules/embark-framework/js/web3.js"
js: js:
src: [ src: [
"app/js/**/*.js" "app/js/**/*.js"
@ -20,11 +22,26 @@ module.exports = (grunt) ->
"app/html/**/*.html" "app/html/**/*.html"
] ]
coffee:
dest: "generated/dapp/compiled-coffee"
compiled: [
"generated/dapp/compiled-coffee/app.coffee"
"generated/dapp/compiled-coffee/**/*.js"
]
contracts: contracts:
src: [ src: [
"app/contracts/**/*.sol" "app/contracts/**/*.sol"
] ]
coffee:
compile:
expand: true
cwd: 'coffee'
src: '**/*.coffee'
dest: '<%= files.coffee.dest %>'
ext: '.js'
concat: concat:
app: app:
src: ["<%= files.web3 %>", 'generated/tmp/abi.js', "<%= files.js.src %>", "<%= files.coffee.compiled %>"] src: ["<%= files.web3 %>", 'generated/tmp/abi.js', "<%= files.js.src %>", "<%= files.coffee.compiled %>"]
@ -33,6 +50,30 @@ module.exports = (grunt) ->
src: "<%= files.css.src %>" src: "<%= files.css.src %>"
dest: "generated/dapp/css/app.min.css" dest: "generated/dapp/css/app.min.css"
watch:
options:
livereload: true
html:
files: ["<%= files.html.src %>"]
tasks: ["copy"]
js:
files: ["<%= files.js.src %>"]
tasks: ["concat"]
css:
files: ["<%= concat.css.src %>"]
tasks: ["concat"]
coffee:
files: ["coffee/**/*.coffee"]
tasks: ["coffee", "concat"]
contracts:
files: ["<%= files.contracts.src %>"]
tasks: ["deploy", "concat", "copy"]
copy: copy:
html: html:
files: files:
@ -45,11 +86,18 @@ module.exports = (grunt) ->
files: files:
"dist/contracts/": '<%= files.contracts.src %>' "dist/contracts/": '<%= files.contracts.src %>'
uglify:
dist:
src: "<%= concat.app.dest %>" # input from the concat process
dest: "dist/dapp/js/app.min.js"
clean:
workspaces: ["dist", "generated"]
deploy: deploy:
contracts: '<%= files.contracts.src %>' contracts: '<%= files.contracts.src %>'
dest: 'generated/tmp/abi.js' dest: 'generated/tmp/abi.js'
) )
)
# loading external tasks (aka: plugins) # loading external tasks (aka: plugins)
# Loads all plugins that match "grunt-", in this case all of our current plugins # Loads all plugins that match "grunt-", in this case all of our current plugins

View File

@ -1,5 +1,5 @@
type: "grunt" #other options: meteor, manual type: "grunt" #other options: meteor, manual
#contracts: ["app/contracts/**"] #contracts: ["app/contracts/**/*.sol"]
#output: "generated/tmp/abi.js" #output: "src/embark.js"
#blockchainConfig: "config/blockchain.yml" #blockchainConfig: "config/blockchain.yml"
#contractsConfig: "config/contracts.yml" #contractsConfig: "config/contracts.yml"

View File

@ -10,7 +10,8 @@
"license": "ISC", "license": "ISC",
"homepage": "", "homepage": "",
"devDependencies": { "devDependencies": {
"embark-framework": "^0.5.0", "embark-framework": "^0.6.0",
"grunt-embark": "0.1.0",
"grunt-contrib-clean": "^0.6.0", "grunt-contrib-clean": "^0.6.0",
"grunt-contrib-coffee": "^0.13.0", "grunt-contrib-coffee": "^0.13.0",
"grunt-contrib-concat": "^0.5.1", "grunt-contrib-concat": "^0.5.1",

View File

@ -0,0 +1,8 @@
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.
notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2

1
demo_meteor/.meteor/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
local

7
demo_meteor/.meteor/.id Normal file
View File

@ -0,0 +1,7 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
v2fbp61wvu7nd11xgkdz

View File

@ -0,0 +1,10 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-platform
autopublish
insecure
ethereum:web3

View File

@ -0,0 +1,2 @@
server
browser

View File

@ -0,0 +1 @@
METEOR@1.1.0.2

View File

@ -0,0 +1,49 @@
autopublish@1.0.3
autoupdate@1.2.1
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.2
blaze-tools@1.0.3
boilerplate-generator@1.0.3
callback-hook@1.0.3
check@1.0.5
ddp@1.1.0
deps@1.0.7
ejson@1.0.6
ethereum:web3@0.8.1
fastclick@1.0.3
geojson-utils@1.0.3
html-tools@1.0.4
htmljs@1.0.4
http@1.1.0
id-map@1.0.3
insecure@1.0.3
jquery@1.11.3_2
json@1.0.3
launch-screen@1.0.2
livedata@1.0.13
logging@1.0.7
meteor@1.1.6
meteor-platform@1.2.2
minifiers@1.1.5
minimongo@1.0.8
mobile-status-bar@1.0.3
mongo@1.1.0
observe-sequence@1.0.6
ordered-dict@1.0.3
random@1.0.3
reactive-dict@1.1.0
reactive-var@1.0.5
reload@1.1.3
retry@1.0.3
routepolicy@1.0.5
session@1.1.0
spacebars@1.0.6
spacebars-compiler@1.0.6
templating@1.1.1
tracker@1.0.7
ui@1.0.6
underscore@1.0.3
url@1.0.4
webapp@1.2.0
webapp-hashing@1.0.3

View File

@ -0,0 +1 @@
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8101'));web3.eth.defaultAccount = web3.eth.accounts[0];SimpleStorageAbi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"type":"function"},{"inputs":[{"name":"initialValue","type":"uint256"}],"type":"constructor"}];SimpleStorageContract = web3.eth.contract(SimpleStorageAbi);SimpleStorage = SimpleStorageContract.at('0x823802b31f5856bcf5a8a99f791934f9593afbf8');

View File

@ -0,0 +1 @@
/* CSS declarations go here */

View File

@ -0,0 +1,29 @@
<head>
<title>Embark - SimpleStorage Demo</title>
</head>
<body>
<h3>Embark - SimpleStorage Demo</h3>
{{> set_value}}
{{> current_value}}
<div class="logs">
</div>
</body>
<template name="current_value">
<div>
<button class="get">Get Value</button>
<br>value is <span class="value">{{value}}</span>
</div>
</template>
<template name="set_value">
<div>
<input type="text" class="text" value="10">
<button class="set">Set Value</button>
</div>
</template>

View File

@ -0,0 +1,35 @@
if (Meteor.isClient) {
Session.setDefault('value', 0);
var addToLog = function(txt) {
$(".logs").append("<br>" + txt);
}
Template.current_value.helpers({
value: function () {
return Session.get('value');
}
});
Template.current_value.events({
'click button': function () {
var value = SimpleStorage.get().toNumber();
Session.set('value', value);
addToLog("SimpleStorage.get()");
}
});
Template.set_value.events({
'click button': function () {
var value = parseInt($("input.text").val(), 10);
SimpleStorage.set(value);
addToLog("SimpleStorage.set("+value+")");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}

View File

@ -0,0 +1,23 @@
development:
rpc_host: localhost
rpc_port: 8101
rpc_whitelist: "*"
minerthreads: 1
datadir: /tmp/embark
mine_when_needed: true
gas_limit: 500000
gas_price: 10000000000000
console: false
account:
init: true
password: config/password
staging:
rpc_host: localhost
rpc_port: 8101
rpc_whitelist: "*"
datadir: default
network_id: 0
console: true
account:
init: false
address:

View File

@ -0,0 +1,8 @@
development:
SimpleStorage:
args:
- 100
staging:
SimpleStorage:
args:
- 100

View File

@ -0,0 +1 @@
dev_password

View File

@ -0,0 +1,14 @@
contract SimpleStorage {
uint public storedData;
function SimpleStorage(uint initialValue) {
storedData = initialValue;
}
function set(uint x) {
storedData = x;
}
function get() constant returns (uint retVal) {
return storedData;
}
}

5
demo_meteor/embark.yml Normal file
View File

@ -0,0 +1,5 @@
type: "meteor"
contracts: ["contracts/**/*.sol"]
output: "client/embark.js"
blockchainConfig: "config/blockchain.yml"
contractsConfig: "config/contracts.yml"

View File

@ -44,7 +44,7 @@ Blockchain.prototype.init_command = function() {
return this.generate_basic_command() + "account new "; return this.generate_basic_command() + "account new ";
} }
Blockchain.prototype.run_command = function(address) { Blockchain.prototype.run_command = function(address, use_tmp) {
var cmd = this.generate_basic_command(); var cmd = this.generate_basic_command();
var config = this.config; var config = this.config;
@ -57,8 +57,13 @@ Blockchain.prototype.run_command = function(address) {
} }
if (config.mine_when_needed) { if (config.mine_when_needed) {
if (use_tmp) {
cmd += "js /tmp/mine.js";
}
else {
cmd += "js node_modules/embark-framework/js/mine.js"; cmd += "js node_modules/embark-framework/js/mine.js";
} }
}
return cmd; return cmd;
} }
@ -84,10 +89,10 @@ Blockchain.prototype.get_address = function() {
return address; return address;
} }
Blockchain.prototype.startChain = function() { Blockchain.prototype.startChain = function(use_tmp) {
var address = this.get_address(); var address = this.get_address();
console.log("running: " + this.run_command(address)); console.log("running: " + this.run_command(address, use_tmp));
exec(this.run_command(address)); exec(this.run_command(address, use_tmp));
} }
module.exports = Blockchain module.exports = Blockchain

View File

@ -30,9 +30,9 @@ Embark = {
return new Tests(this.contractsConfig, contractFiles); return new Tests(this.contractsConfig, contractFiles);
}, },
startBlockchain: function(env) { startBlockchain: function(env, use_tmp) {
var chain = new Blockchain(this.blockchainConfig.config(env)); var chain = new Blockchain(this.blockchainConfig.config(env));
chain.startChain(); chain.startChain(use_tmp);
}, },
deployContracts: function(env, contractFiles, destFile) { deployContracts: function(env, contractFiles, destFile) {

View File

@ -1,10 +1,8 @@
require('shelljs/global'); require('shelljs/global');
ipfs = function() { ipfs = function(build_dir) {
ipfs_path = "~/go/bin"; ipfs_path = "~/go/bin";
build_dir = "dist/dapp/";
cmd = ipfs_path + "/ipfs add -r " + build_dir; cmd = ipfs_path + "/ipfs add -r " + build_dir;
console.log("=== adding " + cmd + " to ipfs"); console.log("=== adding " + cmd + " to ipfs");

View File

@ -1,6 +1,6 @@
{ {
"name": "embark-framework", "name": "embark-framework",
"version": "0.5.0", "version": "0.6.0",
"description": "", "description": "",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
@ -17,17 +17,9 @@
"compression": "^1.4.3", "compression": "^1.4.3",
"express": "^4.12.3", "express": "^4.12.3",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-coffee": "^0.13.0",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-uglify": "^0.9.1",
"grunt-contrib-watch": "^0.6.1",
"grunt-open": "^0.2.3",
"hashmerge": "^1.0.2", "hashmerge": "^1.0.2",
"jasmine": "^2.3.1", "jasmine": "^2.3.1",
"matchdep": "^0.3.0", "meteor-build-client": "^0.1.6",
"methodmissing": "^0.0.3", "methodmissing": "^0.0.3",
"python": "^0.0.4", "python": "^0.0.4",
"read-yaml": "^1.0.0", "read-yaml": "^1.0.0",

View File

@ -1,102 +0,0 @@
module.exports = (grunt) ->
@embarkConfig =
files:
web3:
"node_modules/embark-framework/js/web3.js"
js:
src: [
"app/js/**/*.js"
]
css:
src: [
"app/css/**/*.css"
]
html:
src: [
"app/html/**/*.html"
]
coffee:
dest: "generated/dapp/compiled-coffee"
compiled: [
"generated/dapp/compiled-coffee/app.coffee"
"generated/dapp/compiled-coffee/**/*.js"
]
contracts:
src: [
"app/contracts/**/*.sol"
]
coffee:
compile:
expand: true
cwd: 'coffee'
src: '**/*.coffee'
dest: '<%= files.coffee.dest %>'
ext: '.js'
concat:
app:
src: ["<%= files.web3 %>", 'generated/tmp/abi.js', "<%= files.js.src %>", "<%= files.coffee.compiled %>"]
dest: "generated/dapp/js/app.min.js"
css:
src: "<%= files.css.src %>"
dest: "generated/dapp/css/app.min.css"
watch:
options:
livereload: true
html:
files: ["<%= files.html.src %>"]
tasks: ["copy"]
js:
files: ["<%= files.js.src %>"]
tasks: ["concat"]
css:
files: ["<%= concat.css.src %>"]
tasks: ["concat"]
coffee:
files: ["coffee/**/*.coffee"]
tasks: ["coffee", "concat"]
contracts:
files: ["<%= files.contracts.src %>"]
tasks: ["deploy", "concat", "copy"]
copy:
html:
files:
"generated/dapp/index.html" : "<%= files.html.src %>"
"dist/dapp/index.html" : "<%= files.html.src %>"
css:
files:
"dist/dapp/css/app.min.css" : "<%= files.css.src %>"
contracts:
files:
"dist/contracts/": '<%= files.contracts.src %>'
uglify:
dist:
src: "<%= concat.app.dest %>" # input from the concat process
dest: "dist/dapp/js/app.min.js"
clean:
workspaces: ["dist", "generated"]
deploy:
contracts: '<%= files.contracts.src %>'
dest: 'generated/tmp/abi.js'
@initEmbarkConfig = (userConfig) =>
hashmerge = require('hashmerge')
hashmerge(@embarkConfig, userConfig)

View File

@ -1,9 +0,0 @@
module.exports = (grunt) ->
grunt.registerTask "blockchain", "deploy ethereum node", (env_) =>
env = env_ || "development"
Embark = require('embark-framework')
Embark.init()
Embark.blockchainConfig.loadConfigFile('config/blockchain.yml')
Embark.startBlockchain(env)

View File

@ -1,17 +0,0 @@
module.exports = (grunt) ->
web3 = require('web3')
readYaml = require('read-yaml');
grunt.registerTask "deploy_contracts", "deploy code", (env_) =>
env = env_ || "development"
contractFiles = grunt.file.expand(grunt.config.get("deploy.contracts"));
destFile = grunt.config.get("deploy.dest");
Embark = require('embark-framework')
Embark.init()
Embark.blockchainConfig.loadConfigFile('config/blockchain.yml')
Embark.contractsConfig.loadConfigFile('config/contracts.yml')
#abi = Embark.deployContracts(env, contractFiles, destFile)
abi = Embark.deployContracts(env, contractFiles, destFile)
grunt.file.write(destFile, abi);

View File

@ -1,7 +0,0 @@
module.exports = (grunt) ->
grunt.registerTask "ipfs", "distribute into ipfs", (env_) =>
env = env_ || "development"
Embark = require('embark-framework')
Embark.release.ipfs()

View File

@ -1,21 +0,0 @@
module.exports = (grunt) ->
express = require("express")
compression = require("compression")
readYaml = require('read-yaml')
grunt.registerTask "server", "static file development server", =>
serverConfig = readYaml.sync("config/server.yml")
webPort = serverConfig.port || 8000
webHost = serverConfig.host || 'localhost'
webRoot = "generated/dapp"
app = express()
app.use(compression())
app.use(express.static("" + (process.cwd()) + "/" + webRoot))
app.listen(webPort, webHost)
grunt.log.writeln("Running web server on port http://#{webHost}:#{webPort}")
return app

View File

@ -1,5 +0,0 @@
module.exports = (grunt) ->
grunt.registerTask "deploy", ["coffee", "deploy_contracts", "concat", "copy", "server", "watch"]
grunt.registerTask "build", ["clean", "deploy_contracts", "coffee", "concat", "uglify", "copy"]