2017-03-29 15:37:30 +00:00
let async = require ( 'async' ) ;
2018-04-25 14:34:17 +00:00
const constants = require ( './constants' ) ;
2018-04-30 05:56:43 +00:00
const _ = require ( 'underscore' ) ;
2017-03-12 15:21:19 +00:00
// require("./utils/debug_util.js")(__filename, async);
2017-03-01 04:29:16 +00:00
2017-12-05 23:14:46 +00:00
require ( 'colors' ) ;
2016-08-14 12:04:34 +00:00
2018-04-09 20:14:07 +00:00
// Override process.chdir so that we have a partial-implementation PWD for Windows
const realChdir = process . chdir ;
process . chdir = ( ... args ) => {
if ( ! process . env . PWD ) {
process . env . PWD = process . cwd ( ) ;
}
realChdir ( ... args ) ;
} ;
2017-03-30 13:16:46 +00:00
let Engine = require ( './core/engine.js' ) ;
let version = require ( '../package.json' ) . version ;
2017-03-31 11:34:43 +00:00
class Embark {
2017-03-30 13:16:46 +00:00
constructor ( options ) {
this . version = version ;
this . options = options || { } ;
}
2017-03-30 11:12:39 +00:00
2017-03-30 13:16:46 +00:00
initConfig ( env , options ) {
let Events = require ( './core/events.js' ) ;
let Logger = require ( './core/logger.js' ) ;
let Config = require ( './core/config.js' ) ;
2017-03-30 11:12:39 +00:00
2017-03-30 13:16:46 +00:00
this . events = new Events ( ) ;
2018-03-15 21:18:20 +00:00
this . logger = new Logger ( { logLevel : 'debug' , events : this . events } ) ;
2017-03-30 13:16:46 +00:00
2018-04-25 14:34:17 +00:00
this . config = new Config ( { env : env , logger : this . logger , events : this . events , context : this . context } ) ;
2017-03-30 11:12:39 +00:00
this . config . loadConfigFiles ( options ) ;
this . plugins = this . config . plugins ;
2017-03-30 13:16:46 +00:00
}
2017-03-30 11:12:39 +00:00
2018-05-14 18:32:19 +00:00
isDev ( env ) {
if ( this . config && this . config . blockchainConfig && this . config . blockchainConfig . isDev ) {
return true ;
} else if ( this . config && this . config . blockchainConfig && this . config . blockchainConfig . isDev === false ) {
return false ;
}
return ( env === 'development' ) ;
}
2017-03-30 13:16:46 +00:00
blockchain ( env , client ) {
2018-04-25 14:34:17 +00:00
this . context = [ constants . contexts . blockchain ] ;
2018-04-26 11:37:00 +00:00
let blockchainConfig = this . config . blockchainConfig ;
let storageConfig = this . config . storageConfig ;
let webServerConfig = this . config . webServerConfig ;
if ( blockchainConfig . rpcCorsDomain === 'auto' ) {
if ( webServerConfig ) blockchainConfig . rpcCorsDomain = ` http:// ${ webServerConfig . host } : ${ webServerConfig . port } ` ;
2018-04-30 05:56:43 +00:00
if ( storageConfig ) blockchainConfig . rpcCorsDomain += ` ${ blockchainConfig . rpcCorsDomain . length ? ',' : '' } ${ storageConfig . protocol } :// ${ storageConfig . host } : ${ storageConfig . port } ` ;
2018-04-26 11:37:00 +00:00
}
if ( blockchainConfig . wsOrigins === 'auto' ) {
if ( webServerConfig ) blockchainConfig . wsOrigins = ` http:// ${ webServerConfig . host } : ${ webServerConfig . port } ` ;
2018-04-30 05:56:43 +00:00
if ( storageConfig ) blockchainConfig . wsOrigins += ` ${ blockchainConfig . wsOrigins . length ? ',' : '' } ${ storageConfig . protocol } :// ${ storageConfig . host } : ${ storageConfig . port } ` ;
2018-04-26 11:37:00 +00:00
}
2018-05-14 18:32:19 +00:00
return require ( './cmds/blockchain/blockchain.js' ) ( blockchainConfig , client , env , this . isDev ( env ) ) . run ( ) ;
2017-03-30 13:16:46 +00:00
}
2017-02-25 03:49:34 +00:00
2017-03-30 13:16:46 +00:00
simulator ( options ) {
2018-04-25 14:34:17 +00:00
this . context = options . context || [ constants . contexts . simulator , constants . contexts . blockchain ] ;
2017-03-30 13:16:46 +00:00
let Simulator = require ( './cmds/simulator.js' ) ;
2018-04-27 13:16:29 +00:00
let simulator = new Simulator ( { blockchainConfig : this . config . blockchainConfig , logger : this . logger } ) ;
2017-03-30 13:16:46 +00:00
simulator . run ( options ) ;
}
2017-01-15 23:46:40 +00:00
2017-03-30 13:31:23 +00:00
generateTemplate ( templateName , destinationFolder , name ) {
2018-04-25 14:34:17 +00:00
this . context = [ constants . contexts . templateGeneration ] ;
2017-03-30 13:16:46 +00:00
let TemplateGenerator = require ( './cmds/template_generator.js' ) ;
let templateGenerator = new TemplateGenerator ( templateName ) ;
templateGenerator . generate ( destinationFolder , name ) ;
}
2017-02-25 03:49:34 +00:00
2017-03-30 13:16:46 +00:00
run ( options ) {
2017-03-31 11:34:43 +00:00
let self = this ;
2018-04-25 14:34:17 +00:00
self . context = options . context || [ constants . contexts . run , constants . contexts . build ] ;
2017-03-30 13:16:46 +00:00
let Dashboard = require ( './dashboard/dashboard.js' ) ;
2017-12-19 20:14:09 +00:00
let windowSize = require ( 'window-size' ) ;
2017-03-11 03:00:30 +00:00
2017-03-30 13:16:46 +00:00
let engine = new Engine ( {
env : options . env ,
2018-05-18 19:48:28 +00:00
client : options . client ,
locale : options . locale ,
2018-05-14 18:32:19 +00:00
isDev : this . isDev ( options . env ) ,
2017-03-31 11:34:43 +00:00
version : this . version ,
2018-03-10 18:45:56 +00:00
embarkConfig : options . embarkConfig || 'embark.json' ,
2018-04-19 04:25:43 +00:00
logFile : options . logFile ,
2018-04-25 14:34:17 +00:00
logLevel : options . logLevel ,
context : self . context
2017-03-30 13:16:46 +00:00
} ) ;
engine . init ( ) ;
if ( ! options . useDashboard ) {
2018-04-24 18:42:56 +00:00
engine . logger . info ( '========================' . bold . green ) ;
2018-05-08 21:49:46 +00:00
engine . logger . info ( ( _ _ ( 'Welcome to Embark' ) + ' ' + this . version ) . yellow . bold ) ;
2018-04-24 18:42:56 +00:00
engine . logger . info ( '========================' . bold . green ) ;
2017-03-30 13:16:46 +00:00
}
async . parallel ( [
function startDashboard ( callback ) {
if ( ! options . useDashboard ) {
return callback ( ) ;
}
let dashboard = new Dashboard ( {
2017-12-17 23:34:41 +00:00
events : engine . events ,
2017-03-30 13:16:46 +00:00
logger : engine . logger ,
plugins : engine . plugins ,
2017-03-31 11:34:43 +00:00
version : self . version ,
2017-07-06 23:50:36 +00:00
env : engine . env ,
contractsConfig : engine . config . contractsConfig
2017-03-30 13:16:46 +00:00
} ) ;
dashboard . start ( function ( ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( 'dashboard start' ) ) ;
2017-02-25 20:47:35 +00:00
callback ( ) ;
2017-03-30 13:16:46 +00:00
} ) ;
} ,
function ( callback ) {
let pluginList = engine . plugins . listPlugins ( ) ;
if ( pluginList . length > 0 ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "loaded plugins" ) + ": " + pluginList . join ( ", " ) ) ;
2017-03-30 11:12:39 +00:00
}
2017-03-30 13:16:46 +00:00
engine . startMonitor ( ) ;
2017-12-30 20:52:51 +00:00
engine . startService ( "libraryManager" ) ;
2018-05-23 15:16:56 +00:00
engine . startService ( "codeRunner" ) ;
2017-03-30 13:16:46 +00:00
engine . startService ( "web3" ) ;
engine . startService ( "pipeline" ) ;
engine . startService ( "deployment" ) ;
2018-05-23 15:16:13 +00:00
engine . startService ( "codeGenerator" ) ;
2018-05-19 01:05:39 +00:00
// TODO: this should be just 'storage' and the storage should figure out the module
engine . startService ( engine . config . storageConfig . provider ) ;
2017-03-30 13:16:46 +00:00
engine . events . on ( 'check:backOnline:Ethereum' , function ( ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( 'Ethereum node detected' ) + '..' ) ;
2017-03-30 13:16:46 +00:00
engine . config . reloadConfig ( ) ;
engine . deployManager . deployContracts ( function ( ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( 'Deployment Done' ) ) ;
2017-03-30 13:16:46 +00:00
} ) ;
2016-11-28 20:14:39 +00:00
} ) ;
2017-03-30 13:16:46 +00:00
2018-04-17 04:11:22 +00:00
engine . events . on ( 'outputDone' , function ( ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( ( _ _ ( "Looking for documentation? You can find it at" ) + " " ) . cyan + "http://embark.status.im/docs/" . green . underline + "." . cyan ) ;
engine . logger . info ( _ _ ( "Ready" ) . underline ) ;
engine . events . emit ( "status" , _ _ ( "Ready" ) . green ) ;
2018-04-17 04:11:22 +00:00
} ) ;
2018-05-22 19:46:02 +00:00
engine . onReady ( ( ) => {
2018-05-22 15:07:58 +00:00
engine . deployManager . deployContracts ( function ( err ) {
engine . startService ( "fileWatcher" ) ;
if ( options . runWebserver ) {
engine . startService ( "webServer" , {
host : options . serverHost ,
port : options . serverPort
} ) ;
}
callback ( err ) ;
} ) ;
2017-03-30 11:12:39 +00:00
} ) ;
2017-03-30 13:16:46 +00:00
}
2017-12-05 23:14:46 +00:00
] , function ( err , _result ) {
2017-03-30 13:16:46 +00:00
if ( err ) {
engine . logger . error ( err . message ) ;
engine . logger . info ( err . stack ) ;
2016-10-31 02:04:25 +00:00
} else {
2017-12-19 20:14:09 +00:00
engine . events . emit ( 'firstDeploymentDone' ) ;
let size = windowSize . get ( ) ;
if ( size . height < 40 || size . width < 118 ) {
2018-05-08 21:49:46 +00:00
engine . logger . warn ( _ _ ( "tip: you can resize the terminal or disable the dashboard with" ) + " embark run --nodashboard" . bold . underline ) ;
2017-12-19 20:14:09 +00:00
}
2016-10-31 02:04:25 +00:00
}
2017-03-30 13:16:46 +00:00
} ) ;
}
2018-04-20 07:39:45 +00:00
build ( options ) {
2018-04-25 14:34:17 +00:00
this . context = options . context || [ constants . contexts . build ] ;
2018-04-26 09:05:56 +00:00
2018-04-19 04:25:43 +00:00
let engine = new Engine ( {
env : options . env ,
2018-05-22 19:46:02 +00:00
client : options . client ,
locale : options . locale ,
2018-05-14 18:32:19 +00:00
isDev : this . isDev ( options . env ) ,
2018-04-19 04:25:43 +00:00
version : this . version ,
embarkConfig : 'embark.json' ,
interceptLogs : false ,
logFile : options . logFile ,
logLevel : options . logLevel ,
events : options . events ,
logger : options . logger ,
config : options . config ,
2018-04-25 14:34:17 +00:00
plugins : options . plugins ,
context : this . context
2018-04-19 04:25:43 +00:00
} ) ;
engine . init ( ) ;
2016-10-02 21:26:57 +00:00
2017-03-30 13:16:46 +00:00
async . waterfall ( [
function startServices ( callback ) {
let pluginList = engine . plugins . listPlugins ( ) ;
if ( pluginList . length > 0 ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "loaded plugins" ) + ": " + pluginList . join ( ", " ) ) ;
2017-03-30 13:16:46 +00:00
}
2017-12-30 20:52:51 +00:00
engine . startService ( "libraryManager" ) ;
2018-05-23 15:16:56 +00:00
engine . startService ( "codeRunner" ) ;
2017-03-30 13:16:46 +00:00
engine . startService ( "web3" ) ;
engine . startService ( "pipeline" ) ;
2018-05-17 20:37:57 +00:00
engine . startService ( "deployment" , { onlyCompile : options . onlyCompile } ) ;
2018-05-23 15:16:13 +00:00
engine . startService ( "codeGenerator" ) ;
2018-05-19 01:05:39 +00:00
// TODO: this should be just 'storage' and the storage should figure out the modules to load
2017-12-30 20:52:51 +00:00
engine . startService ( "ipfs" ) ;
2018-05-19 01:05:39 +00:00
engine . startService ( "swarm" ) ;
2017-03-30 13:16:46 +00:00
callback ( ) ;
} ,
function deploy ( callback ) {
2018-05-22 19:46:02 +00:00
engine . onReady ( ( ) => {
2018-05-22 19:45:21 +00:00
engine . deployManager . deployContracts ( function ( err ) {
callback ( err ) ;
} ) ;
2017-03-30 13:16:46 +00:00
} ) ;
}
2017-12-05 23:14:46 +00:00
] , function ( err , _result ) {
2017-03-30 13:16:46 +00:00
if ( err ) {
engine . logger . error ( err . message ) ;
engine . logger . debug ( err . stack ) ;
} else {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "finished building" ) . underline ) ;
2017-03-30 13:16:46 +00:00
}
// needed due to child processes
2018-04-20 07:39:45 +00:00
process . exit ( ) ;
2017-03-30 13:16:46 +00:00
} ) ;
}
2017-03-30 13:31:23 +00:00
initTests ( options ) {
2018-04-25 14:34:17 +00:00
this . context = options . context || [ constants . contexts . test ] ;
2018-01-20 02:13:20 +00:00
let Test = require ( './tests/test.js' ) ;
2018-04-25 14:34:17 +00:00
options . context = this . context ;
2017-03-30 13:16:46 +00:00
return new Test ( options ) ;
}
2018-03-22 19:09:01 +00:00
graph ( options ) {
2018-04-25 14:34:17 +00:00
this . context = options . context || [ constants . contexts . graph ] ;
2018-03-22 19:09:01 +00:00
options . onlyCompile = true ;
let engine = new Engine ( {
env : options . env ,
2018-05-14 18:32:19 +00:00
isDev : this . isDev ( options . env ) ,
2018-03-22 19:09:01 +00:00
version : this . version ,
embarkConfig : options . embarkConfig || 'embark.json' ,
2018-04-25 14:34:17 +00:00
logFile : options . logFile ,
context : this . context
2018-03-22 19:09:01 +00:00
} ) ;
engine . init ( ) ;
async . parallel ( [
2018-05-08 21:49:46 +00:00
2018-03-22 19:09:01 +00:00
function ( callback ) {
let pluginList = engine . plugins . listPlugins ( ) ;
if ( pluginList . length > 0 ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "loaded plugins" ) + ": " + pluginList . join ( ", " ) ) ;
2018-03-22 19:09:01 +00:00
}
engine . startMonitor ( ) ;
engine . startService ( "libraryManager" ) ;
engine . startService ( "pipeline" ) ;
engine . startService ( "deployment" , { onlyCompile : true } ) ;
2018-05-23 15:16:13 +00:00
engine . startService ( "codeGenerator" ) ;
2018-03-22 19:09:01 +00:00
engine . deployManager . deployContracts ( function ( err ) {
callback ( err ) ;
} ) ;
}
2018-05-04 20:17:12 +00:00
] , ( err , _result ) => {
2018-03-22 19:09:01 +00:00
if ( err ) {
engine . logger . error ( err . message ) ;
engine . logger . info ( err . stack ) ;
} else {
const GraphGenerator = require ( './cmds/graph.js' ) ;
2018-03-22 20:18:13 +00:00
let graphGen = new GraphGenerator ( engine ) ;
2018-05-04 20:17:12 +00:00
graphGen . generate ( options ) ;
2018-03-22 19:09:01 +00:00
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "Done. %s generated" , "./diagram.svg" ) . underline ) ;
2018-03-22 19:09:01 +00:00
process . exit ( ) ;
}
} ) ;
2018-03-22 14:43:29 +00:00
}
2018-01-11 14:22:58 +00:00
reset ( ) {
2018-04-25 14:34:17 +00:00
this . context = [ constants . contexts . reset ] ;
2018-01-11 14:22:58 +00:00
let resetCmd = require ( './cmds/reset.js' ) ;
resetCmd ( ) ;
}
2018-05-17 07:38:17 +00:00
upload ( options ) {
2018-05-08 21:49:46 +00:00
2018-04-26 09:05:56 +00:00
this . context = options . context || [ constants . contexts . upload , constants . contexts . build ] ;
2018-04-19 04:25:43 +00:00
2018-04-20 07:39:45 +00:00
let engine = new Engine ( {
env : options . env ,
2018-05-14 18:32:19 +00:00
isDev : this . isDev ( options . env ) ,
2018-04-20 07:39:45 +00:00
version : this . version ,
embarkConfig : 'embark.json' ,
interceptLogs : false ,
logFile : options . logFile ,
logLevel : options . logLevel ,
events : options . events ,
logger : options . logger ,
config : options . config ,
plugins : options . plugins
} ) ;
engine . init ( ) ;
2018-05-17 07:38:17 +00:00
let platform = engine . config . storageConfig . provider ;
2017-12-27 00:55:42 +00:00
let cmdPlugin ;
2018-04-15 08:41:50 +00:00
async . waterfall ( [
2018-05-08 21:49:46 +00:00
2018-04-24 00:27:11 +00:00
function startServices ( callback ) {
2018-05-08 21:49:46 +00:00
2018-04-24 00:27:11 +00:00
engine . startService ( "libraryManager" ) ;
2018-05-23 15:16:56 +00:00
engine . startService ( "codeRunner" ) ;
2018-04-24 00:27:11 +00:00
engine . startService ( "web3" ) ;
engine . startService ( "pipeline" ) ;
engine . startService ( "deployment" ) ;
2018-05-23 15:16:13 +00:00
engine . startService ( "codeGenerator" ) ;
2018-05-19 01:05:39 +00:00
// TODO: this should be just 'storage' and the storage should figure out the modules to load
engine . startService ( platform . toLowerCase ( ) ) ;
2018-04-30 05:56:43 +00:00
engine . startMonitor ( ) ;
2018-04-24 00:27:11 +00:00
callback ( ) ;
} ,
2018-04-30 05:56:43 +00:00
function checkStorageService ( callback ) {
let checkFn ;
_ . find ( engine . servicesMonitor . checkList , ( value , key ) => {
if ( key . toLowerCase ( ) === platform . toLowerCase ( ) ) {
checkFn = value ;
return true ;
}
} ) ;
2018-05-01 13:38:13 +00:00
if ( ! checkFn || typeof checkFn . fn !== 'function' ) {
return callback ( ) ;
2018-04-30 05:56:43 +00:00
}
2018-05-01 13:38:13 +00:00
checkFn . fn ( function ( serviceCheckResult ) {
if ( ! serviceCheckResult . status || serviceCheckResult . status === 'off' ) {
2018-05-17 07:38:17 +00:00
return callback ( { message : _ _ ( 'Cannot upload: {{platform}} node is not running on {{protocol}}://{{host}}:{{port}}.' , { platform : platform , protocol : engine . config . storageConfig . protocol , host : engine . config . storageConfig . host , port : engine . config . storageConfig . port } ) } ) ;
2018-05-01 13:38:13 +00:00
}
callback ( ) ;
} ) ;
2018-04-30 05:56:43 +00:00
} ,
2018-04-15 08:41:50 +00:00
function setupStoragePlugin ( callback ) {
2018-04-24 00:27:11 +00:00
let pluginList = engine . plugins . listPlugins ( ) ;
if ( pluginList . length > 0 ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "loaded plugins" ) + ": " + pluginList . join ( ", " ) ) ;
2018-04-24 00:27:11 +00:00
}
2018-05-08 21:49:46 +00:00
2018-04-15 08:41:50 +00:00
// check use has input existing storage plugin
2018-04-24 00:27:11 +00:00
let cmdPlugins = engine . plugins . getPluginsFor ( 'uploadCmds' ) ;
2018-05-08 21:49:46 +00:00
2018-04-15 08:41:50 +00:00
if ( cmdPlugins . length > 0 ) {
cmdPlugin = cmdPlugins . find ( ( pluginCmd ) => {
2018-04-26 18:00:41 +00:00
return pluginCmd . uploadCmds . some ( uploadCmd => {
return uploadCmd . cmd === platform ;
} ) ;
2018-04-12 10:46:04 +00:00
} ) ;
}
2018-04-15 08:41:50 +00:00
if ( ! cmdPlugin ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( 'try "{{ipfs}}" or "{{swarm}}"' , { ipfs : 'embark upload ipfs' , swarm : 'embark upload swarm' } ) . green ) ;
2018-05-01 13:38:13 +00:00
return callback ( { message : 'unknown platform: ' + platform } ) ;
2018-04-12 10:46:04 +00:00
}
2018-05-01 13:38:13 +00:00
callback ( ) ;
2018-04-15 08:41:50 +00:00
} ,
2018-04-20 07:39:45 +00:00
function deploy ( callback ) {
2018-04-15 08:41:50 +00:00
// 2. upload to storage (outputDone event triggered after webpack finished)
2018-04-24 00:27:11 +00:00
engine . events . on ( 'outputDone' , function ( ) {
cmdPlugin . uploadCmds [ 0 ] . cb ( )
2018-04-15 08:41:50 +00:00
. then ( ( success ) => {
callback ( null , success ) ;
} )
. catch ( callback ) ;
} ) ;
// 1. build the contracts and dapp webpack
2018-04-20 07:39:45 +00:00
engine . deployManager . deployContracts ( function ( err ) {
2018-05-08 21:49:46 +00:00
engine . logger . info ( _ _ ( "finished deploying" ) . underline ) ;
2018-04-20 07:39:45 +00:00
if ( err ) {
callback ( err ) ;
}
} ) ;
2018-04-15 08:41:50 +00:00
}
] , function ( err , _result ) {
if ( err ) {
2018-04-24 00:27:11 +00:00
engine . logger . error ( err . message ) ;
engine . logger . debug ( err . stack ) ;
2018-04-15 08:41:50 +00:00
} else {
2018-05-08 21:49:46 +00:00
engine . logger . info ( ( _ _ ( "finished building DApp and deploying to" ) + " " + platform ) . underline ) ;
2018-04-15 08:41:50 +00:00
}
2018-04-12 10:46:04 +00:00
2018-04-15 08:41:50 +00:00
// needed due to child processes
process . exit ( ) ;
} ) ;
2017-03-29 15:37:30 +00:00
}
2017-07-02 15:32:16 +00:00
runTests ( file ) {
2018-04-25 14:34:17 +00:00
this . context = [ constants . contexts . test ] ;
2018-01-20 02:13:20 +00:00
let RunTests = require ( './tests/run_tests.js' ) ;
2017-07-02 15:32:16 +00:00
RunTests . run ( file ) ;
2017-07-02 03:11:42 +00:00
}
2017-03-30 13:16:46 +00:00
}
2017-03-12 02:49:12 +00:00
2017-06-26 13:01:54 +00:00
// temporary until next refactor
Embark . initTests = function ( options ) {
2018-01-20 02:13:20 +00:00
let Test = require ( './tests/test.js' ) ;
2018-04-25 14:34:17 +00:00
options . context = [ constants . contexts . test ] ;
2017-06-26 13:01:54 +00:00
return new Test ( options ) ;
2017-06-26 13:02:58 +00:00
} ;
2017-06-26 13:01:54 +00:00
2016-08-18 00:29:41 +00:00
module . exports = Embark ;