Comparar commits

..

91 Commits

Autor SHA1 Mensagem Data
Brian Broll 1578886584 v0.14.0 2016-08-22 07:04:42 -05:00
Brian Broll 0927c2c270 Added npm install instructions 2016-08-20 15:08:45 -05:00
Brian Broll bd329bdfe3 Forwarded stdin to subprocess. Fixes #737 (#738)
WIP #737 Added stdin forwarding

WIP #737 Fixed rnn installation

WIP #737 Updated tests
2016-08-20 11:25:49 -05:00
Brian Broll e3a499f409 Improved error handling on torch install. Fixes #705 (#736)
WIP #705

WIP #705 Fixed error detection on torch install

WIP #705 Changed to Q promises

WIP #705 Updated tests
2016-08-20 08:45:52 -05:00
Brian Broll 63c78426d3 Downgraded nvd3 to v1.8.2. Fixes #593 (#735) 2016-08-19 16:05:27 -05:00
Brian Broll 6ec2f69268 Set y axis precision to 2 places. Fixes #674 (#734) 2016-08-19 15:38:33 -05:00
Brian Broll 1ccd193ddd Hide lines w/ no points. Fixes #732 (#733) 2016-08-19 15:07:28 -05:00
Brian Broll a5d52dce33 Added exec abbreviations when multiple selected in index. Fixes #675 (#731)
WIP #675 Added execIds to executions in ExecIndex

WIP #675 Updated line name if multi execs showing

WIP #675 show execution abbreviation if needed

WIP #675 Fixed code climate issues
2016-08-19 14:51:46 -05:00
Brian Broll ca358ae7b9 Added custom layers to the nn import mock. Fixes #729 (#730) 2016-08-19 11:43:21 -05:00
Brian Broll 0a1177c299 Created tag after execution saved. Fixes #727 (#728) 2016-08-19 11:42:14 -05:00
Brian Broll 46bf346c5c Added symlink to node_modules. Fixes #724 (#725) 2016-08-19 09:55:50 -05:00
Brian Broll 8a94496e01 Added "worker.dir" to config. Fixes #721 (#723) 2016-08-19 08:58:16 -05:00
Brian Broll d3cf339856 Created new directory for each worker. Fixes #720 (#722) 2016-08-19 08:47:20 -05:00
Brian Broll 5c0c58c3be Debounced execution widget updates. Fixes #713 (#719) 2016-08-18 15:10:45 -05:00
Brian Broll ef607e0e76 Removed forever-monitor from cli. Fixes #714 (#717)
WIP #714 Updated tests
2016-08-18 13:47:11 -05:00
Brian Broll 305503ac7a Changed title rename to single click. Fixes #715 (#716) 2016-08-18 12:41:55 -05:00
Brian Broll c76e62b976 Updated creation fn to use places promise. Fixes #710 (#711) 2016-08-17 16:03:14 -05:00
Brian Broll 554065ee11 Updated DeepForge.places to use promises. Fixes #681 (#709)
WIP #681 Added comments for work to be done and some place loading support

WIP #681 changed places to use promises

WIP #681 Updated MainView to use places promises
2016-08-17 15:27:32 -05:00
Brian Broll 7fba52ad97 Added shift-enter to restart jobs/execs/etc. Fixes #641 (#708)
WIP #641 Added key listener for floating action button

WIP #641 Ignored shift+enter in code editor

WIP #641 Fixed shift-enter to restart job

WIP #641 Added shift-enter for execution view

WIP #641 Fixed code climate issues
2016-08-17 13:33:43 -05:00
Brian Broll c56de24e7d Added ctrl-alt-pagedown/up to jump to EOF/beginning in logs. Fixes #667 (#707) 2016-08-17 09:45:53 -05:00
Brian Broll 6e16087fc3 Set the ArtifactLoader name to target in execution view. Fixes #574 (#706)
WIP #574 Added comments for modification locations

WIP #574 Added ArtifactLoader check

WIP #574 Set ArtifactLoader name to the pointer value
2016-08-16 16:07:54 -05:00
Brian Broll 8133acbb46 Added execution duration to ExecIndex. Fixes #628 (#704)
WIP #628 Added execution time support

WIP #628 Removed endTime on execution start

WIP #628 Added startTime, endTime to execution

WIP #628 updated pipeline lib
2016-08-16 11:14:24 -05:00
Brian Broll d974cb8215 Added margin to bottom of log viewer. Fixes #696 (#702)
WIP #696 Added 5 lines to bottom of log file

WIP #696 Set scroll margin to 75px (from bottom)
2016-08-16 10:02:25 -05:00
Brian Broll 68021c1903 Removed \u0000 from stdout logs. Fixes #700 (#701) 2016-08-16 09:55:27 -05:00
Brian Broll 7178b89578 Added better error handling for ops w/ old refs. Fixes #698 (#699) 2016-08-16 09:01:58 -05:00
Brian Broll 0935abe858 Added operation attributes to jobs in ExecutionView. Fixes #686 (#697)
WIP #686 Added opAttributes

WIP #686 Added readonly pointer, attr to job
2016-08-16 07:54:55 -05:00
Brian Broll 22225922e5 Added support for \r in job logs. Fixes #298 (#695)
WIP #298 Adding progress bar support...

WIP #298 Updated stdout logs for \r support
2016-08-15 15:25:12 -05:00
Brian Broll 343f2ffa61 Updated breadcrumb header. Fixes #662 (#694)
WIP #662 Set cachePrefix for path storage

WIP #662 Updated breadcrumbheader version
2016-08-15 12:40:42 -05:00
Brian Broll 477d38d313 Added unknown ref type error and setting. Fixes #690 (#692)
WIP #690 Added viz feedback about unknown type

WIP #690 Starting to add ref type setting

WIP #690 Added click fn-ality. still has bad error tooltip

WIP #690 Replaced baseName tooltip on ref set

WIP #690 Fixed code climate issues
2016-08-15 12:08:42 -05:00
Brian Broll 84e5377b8a Changed template settings to defaults. Fixes #691 (#693) 2016-08-15 12:08:36 -05:00
Brian Broll 1abbecc54c v0.13.0 2016-08-15 10:07:40 -05:00
Brian Broll af2f34545b Added basic table literal support. Fixes #652 (#689) 2016-08-12 17:05:03 -05:00
Brian Broll f7499c4599 Added more robust layer parsing to LayerEditor. Fixes #670 (#688)
WIP #670 Added most LayerParser fn-ality

WIP Fixed error w/ changing arch editors

WIP #670 Added pointer, setter support in layer editor

WIP #670 Updated for layer-as-args

WIP #670 Fixed ctor_arg_order setting

WIP #670 Removed unused fn
2016-08-12 15:59:10 -05:00
Brian Broll ad52fe7d70 Removed containing dir info from stack trace. Fixes #668 (#687) 2016-08-12 15:30:16 -05:00
Brian Broll 5ddeb6f331 Added layers-as-arguments. Fixes #654 (#684)
WIP #654 Added LayerDecorator

WIP #654

WIP #654 Added support for adding/removing layers

WIP #654 Fixed the text for the layers

WIP #654 Refactored content text

WIP #654 Only delete target if it's a child

WIP #654 Updated for layers-as-args

WIP #654 Made a better name for layer args

WIP #654 Added explicit arg types

WIP #654 Changed argindex -> ctor_arg_order

WIP #654 Added support for layers-as-args in GenArch

WIP #654 Added import fn-ality

WIP #654 Updated visualizers for layer support

WIP #654 Fixed code climate issues

WIP #654 Fixed setter detection

WIP #654 Updated tests

WIP #654 Updated tests
2016-08-12 14:28:54 -05:00
Brian Broll 7cd3d961cf Added naming executions. Fixes #683 (#685)
WIP #683 Removed issue from merge w/ master

WIP #683 Updated googlenet test
2016-08-12 13:43:26 -05:00
Brian Broll c38b38b4a1 Added more logging to better debug failures in the future. Fixes #660 (#680)
WIP #660 Added more logs

WIP #660 Added more logs during execution creation

WIP #660 Added more logging for starting executions
2016-08-12 09:54:13 -05:00
Brian Broll 6ae73ece70 Added edit icon for custom layers. Fixes #678 (#679) 2016-08-11 21:33:16 -05:00
Brian Broll b5512d8228 Added better error handling when blob changed. Fixes #659 (#677) 2016-08-11 17:03:48 -05:00
Brian Broll 89c871412a Remove territory ui on ExecIndex destroy. Fixes #673 (#676) 2016-08-11 16:42:13 -05:00
JimnyCricket 33e28aa3f1 Filter non-numbers before graphing. Fixes #671 (#672)
WIP #671 Fixed code climate issues
2016-08-11 16:16:07 -05:00
Brian Broll 3899c3cb16 Added attr type inference in parser. Fixes #655 (#669)
WIP #655 Added type inference based on defaults

WIP #655 removed extra console.log

WIP #655 Inferring type from assertions

WIP #655 Fixed some parsing bugs

WIP #655 Added better type inference

WIP #655 Using types in metamodel creation

WIP #655 Added types

WIP #655 Updated nn library

WIP #655 Fixed code climate issues
2016-08-11 13:22:06 -05:00
Brian Broll eb4f97e9b5 Added check for points before graphing. Fixes #663 (#665)
WIP #663 Removed empty point text
2016-08-11 12:29:14 -05:00
JimnyCricket 16e37043f4 Added type checking for x,y in graph. Fixes #664 (#666)
Changed to single assertion with more info

WIP #664 "Expected" -> "expected"
2016-08-11 11:45:32 -05:00
Brian Broll 261ffd1eba Update README.md (#657) 2016-08-10 15:20:10 -05:00
Brian Broll 9167b33e18 Added configurable worker.cache.dir and worker.cache.useBlob. Fixes #638 (#653)
WIP #638 Added config schema

WIP #638 Added default cache location

WIP #638 Added useBlob fn-ality

WIP #638 Added type checking

WIP #638 Fixed config merge issue

WIP #638 Create worker cache parent dir if needed
2016-08-10 08:23:44 -05:00
Brian Broll 6f7f0d01e5 Added check for undefined value. Fixes #650 (#651) 2016-08-09 16:39:20 -05:00
Brian Broll c11b1fe812 Added blob.dir configuration. Fixes #639 (#649)
WIP #639 Added config schema

WIP #639 Added blob.dir config value
2016-08-09 14:57:32 -05:00
Brian Broll 306425cae1 Added implicit require 'nn' to ImportTorch. Fixes #644 (#647)
WIP #644 Added test
2016-08-09 14:14:04 -05:00
Brian Broll 6d70728b54 Added recurrent layers. Fixes #477 (#645)
WIP #477 Added skipArgs and rnn parsing support

WIP #477 Added update script and updated CreateTorchMeta

WIP #477 Run update script after nn-parser

WIP #477 Simplified nn-parser usage (just 'rnn' or 'nn')

WIP #477 Added 'all' option

WIP #477 Updated the nn project

WIP #477 `require 'rnn'` => nop in importer

WIP #477 Updated gen arch

WIP #477 Updated update --torch

WIP #477 Added rnn installation to torch install

WIP #477 Fixed code climate issues
2016-08-09 13:50:19 -05:00
Brian Broll fadb654883 Create worker dir if doesn't exist. Fixes #643 (#646) 2016-08-09 13:49:13 -05:00
Brian Broll 6528bbdbc6 Clearing output viewer territory on destroy. Fixes #622 (#642) 2016-08-09 07:50:19 -05:00
Brian Broll 23852de607 Set the cache to blob in 'local' mode. Fixes #637 (#640) 2016-08-08 12:43:37 -05:00
Brian Broll 9cf66a0e02 Added caching support to workers. Fixes #616 (#636)
WIP #616 Added cache dir if doesn't exist

WIP #616 Removed data from execution files

WIP #616 Added pointer files to data download

WIP #616 Fixed symlink creation
2016-08-08 12:16:30 -05:00
Brian Broll ad19e0fb57 v0.12.0 2016-08-08 08:30:01 -05:00
Brian Broll 14f222bf6f Merge branch '624-large-files-fail-exec' 2016-08-04 15:23:00 -05:00
Brian Broll 95141d1a42 Added image counter for uploading. Fixes #625 (#632) 2016-08-04 15:14:26 -05:00
Brian Broll 93aaf72372 Added explicit data download on worker. Fixes #624
WIP #624 Missing parens
2016-08-04 15:11:02 -05:00
Brian Broll 47a6612ed0 Added anchor detection on output type click. Fixes #626 (#631) 2016-08-04 14:37:15 -05:00
Brian Broll fe48af8bf4 Created unique worker config and cleanup on close. Fixes #618 (#623) 2016-08-04 10:55:06 -05:00
Brian Broll 78ca4f8762 Added error logs for more complex errors. Fixes #620 (#621)
WIP #620 Added error message to stdout

WIP #620 Added colors and console message
2016-08-04 10:01:36 -05:00
Brian Broll a7e08aa279 Update attributes on cancel job. Fixes #617 (#619)
WIP #617 moved client edits out of promise

WIP #617 Made 'isRunning' more robust

WIP #617 Fixed client calls
2016-08-04 08:37:09 -05:00
Brian Broll e2980d616f Filter out all non-alphanumeric or _ chars in execution. Fixes #612 (#614) 2016-08-03 16:55:02 -05:00
Brian Broll 96f2090d9e Removed long error message on failed exec. Fixes #608 (#611) 2016-08-03 15:55:04 -05:00
Brian Broll 8a86a114db Updated Materialize to explicit require (~global). Fixes #607 (#610) 2016-08-03 15:44:31 -05:00
Brian Broll cb757da118 Added torch config dir check before update. Fixes #606 (#609) 2016-08-03 15:36:43 -05:00
Brian Broll 31711e079a Enabled autoMerge. Fixes #332 Fixes #346 (#605) 2016-08-03 14:02:11 -05:00
Brian Broll 16ebb83ae6 Hiding restart button when running. Fixes #597 (#604) 2016-08-03 13:49:17 -05:00
Brian Broll 65304b2645 Changed SNAPSHOT->DEBUG. Fixes #601 (#603) 2016-08-03 13:18:41 -05:00
Brian Broll b44c6a104b Added execution canceling. Fixes #481 (#602)
WIP #481 Added buttons and jobId, secret setting

WIP #481 Added 'jobId', 'secret' to Job

WIP #481 Canceling job exec support

WIP #481 Added canceling executing pipelines

WIP #481 Fixed canceling pipelines

WIP #481 Improved result messages from executions

WIP #481 Updated decorator and status setting for ExecJob

WIP #481 Updated job colors in lists

WIP #481 Updated pipeline library

WIP #481 Fixed code climate issues
2016-08-03 12:42:55 -05:00
Brian Broll a8e5876f83 Updated fab icon colors. Fixes #588 (#599) 2016-08-03 08:41:24 -05:00
Brian Broll 2d9d1e71c0 Added "complete" notification if exec forked. Fixes #596 (#598)
WIP #596 Added quotes around job, exec, branch for consistency
2016-08-03 08:37:24 -05:00
Brian Broll 475bdfed50 Added notification on fork to ExecuteJob. Fixes #591 (#595)
WIP #591 Added notification on fork to ExecuteJob

WIP #591 Fixed fork name creation
2016-08-03 08:16:04 -05:00
Brian Broll c36f12ccb2 Added Execution dashboard. Fixes #587 (#594)
WIP #587 Added toggling embedded viz

WIP #587 Added ExecutionIndex

WIP #587 Added exec table and rows

WIP #587 Added status colors

WIP #587 Added color coded by status

WIP #587 Retrieved graphs for each execution

WIP #587 Added lineGraph object in right split

WIP #587 Fixed lineGraph resize and added multiple lines

WIP #587 Fixed line updates/removal

WIP #587 Added execution selection

WIP #587 Added execution toggling

WIP #587 Fixed untoggle-able after update

WIP #587 Fixed exec status color updates

WIP #578 Exec name click -> navigate to the given execution

WIP #587 Added pipeline names

WIP #587 Added default 'checking' and pipeline name updates

WIP #587 Fixed the deselection of running execs

WIP #587 Fixed initial pipeline names

WIP #587 Added toggling visualizers

WIP #587 Fixed positioning

WIP #587 Added more logs and fixed pipeline name finding

WIP #587 Fixed project switching and obj changed

WIP #587 Improved perf of chart
2016-08-02 16:42:28 -05:00
Brian Broll 0b8b5b8adf Added decimal to number chars in graph plotting. Fixes #589 (#590) 2016-08-02 11:56:50 -05:00
Brian Broll e981c97c71 v0.11.0 2016-08-01 09:21:51 -05:00
Brian Broll 748461f3c6 Added more flexible ansi code detection. Fixes #582 (#584)
WIP #582 Added better ansi regex

WIP #582 Fixed infinite loop
2016-08-01 09:17:22 -05:00
Brian Broll a51f55dd66 Added operation 'attributes' autocompletions. Fixes #578 (#581) 2016-07-31 17:36:05 -05:00
Brian Broll 7ba2c59265 Propagate the exit code of child process to parent. Fixes #579 (#580) 2016-07-31 07:57:45 -05:00
Brian Broll dcc833a957 Update README.md 2016-07-30 13:11:53 -05:00
Brian Broll 8c35af6554 Added output icons in the job editor. Fixes #576 (#577) 2016-07-30 12:58:12 -05:00
Brian Broll 70fe60a45d Added 'deepforge.image(<name>, <tensor>)' support. Fixes #519 (#575)
WIP #519 Added saving image file on worker

WIP #519 Added wrapper for the intermediate data results

WIP #519 filename->name and silenced blobClient logs

WIP #519 Removed old debug log

WIP #519 Added Image metadata creation

WIP #519 Added ImageViewer

WIP #519 Added zoom fn-ality

WIP #519 Added 'Image' node

WIP #519 Updated pipeline libraries

WIP #519 Added 'image' to deepforge autocomplete

WIP #519 Added no-image image

WIP #519 Fixed image updating

WIP #519 Added better origin url detection

WIP #519 Fixed code climate issues

WIP #519 fixed code climate issues
2016-07-30 11:06:46 -05:00
Brian Broll 98c64fc37a Added custom class inheritance support. Fixes #412 (#573)
WIP #412 Added inheritance setting/unsetting based on code

WIP #412 Fixed ordering of the base class loading

WIP #412 Set test timeout to 5s
2016-07-29 12:04:46 -05:00
Brian Broll efa88194a1 Merged 'snapshot', 'debug' options. Fixes #570 (#572) 2016-07-29 11:38:07 -05:00
Brian Broll f1a5fb18e9 Added basic torch, deepforge code completion. Fixes #565 (#567)
WIP #565 Added entire ace lib. Added dummy completer

WIP #565 Added torch, deepforge completion

WIP #565 Fixed code climate issue

WIP #565 Fixed nodejs ci version
2016-07-28 16:16:54 -05:00
Brian Broll 084f79c51a Removed connection selection in op interface. Fixes #566 (#568) 2016-07-28 15:21:13 -05:00
Brian Broll 2561b1c43a Removed special characters during metadata cmds. Fixes #562 (#563)
WIP #562 Added cleaning the ansi codes from metadata cmds

WIP #562 Fixed point parsing

WIP #562 Cleaning x,y point text
2016-07-28 13:17:03 -05:00
Brian Broll a0b20408fd Fixed running ExecutePipeline on server. Fixes #558 (#561)
WIP #558 Fixed running ExecutePipeline on server

WIP #558 attempted to implement ExecutePipeline tests...

WIP #558 Fixed running ExecutePipeline on server

WIP #558 Removed extra TODO and extra files
2016-07-27 18:18:11 -05:00
Brian Broll 5f3bf23a6a Added xor example. Fixes #557 (#560)
WIP #557 xor example

WIP #557 Added test, train and manual train pipelines
2016-07-27 13:10:15 -05:00
Brian Broll 4badd0d001 Added check for existing artifact w/ same name, hash. Fixes #544 (#555)
WIP #544 Fixed code climate issue
2016-07-27 09:36:29 -05:00
Brian Broll 383eda1f2b Added 'setter' support and default attr detection. Fixes #541 Fixes #553 (#554)
WIP #541 Refactored nn-parser for better reusability

WIP #541 Added setter support to the parser script

WIP #541 Added check for class method match

WIP #541 Added default detection

WIP #541 Added setter support in CreateTorchMeta

WIP #541 Added setters to layer-args.js

WIP #541 Added setter support in ImportTorch

WIP #541 Updated ImportTorch tests

WIP setPointer -> setBase

WIP #541 Updated ImportTorch examples

WIP #541 added setter attributes

WIP #541 Added setter support for GenArch

WIP #541 Updated the GenArch tests

WIP #541 Fixed utils tests

WIP #541 Updated nn library

WIP #541 Removed 'const' setters w/ only one value

WIP #541 Added setter creation test

WIP #541 Updated to use torch from deepforge config, if exists

WIP #541 Fixed code climate issues

WIP #541 skipping broken tests until webgme error is resolved

WIP #541 Updated nn seed after removing meaningless 'const' setters
2016-07-27 09:36:21 -05:00
1132 arquivos alterados com 319061 adições e 36063 exclusões
+1 -2
Ver Arquivo
@@ -2,5 +2,4 @@ language: node_js
services: mongodb
sudo: false
node_js:
- "4.1.1"
- "4.2.5"
- "6.2.1"
+9 -1
Ver Arquivo
@@ -16,9 +16,17 @@ Simply run the following command to install deepforge with its dependencies:
curl -o- https://raw.githubusercontent.com/dfst/deepforge/master/install.sh | bash
```
Or, if you already have NodeJS (v6) installed, simply run
```
npm install -g deepforge
```
Next, start deepforge with `deepforge start`!
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions,check out our [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
Finally, navigate to [http://localhost:8888](http://localhost:8888) to start using DeepForge! For more, detailed instructions, check out the [wiki](https://github.com/dfst/deepforge/wiki/Installation-Guide).
Also, be sure to check out the other available features of the `deepforge` cli; it can be used to update, manage your torch installation, uninstall deepforge and run individual components!
## Interested in contributing?
Contributions are welcome! Either fork the project and submit some PR's or shoot me an email about getting more involved!
+10
Ver Arquivo
@@ -2,6 +2,16 @@
"torch": {
"dir": "~/.deepforge/torch"
},
"blob": {
"dir": "~/.deepforge/blob"
},
"worker": {
"cache": {
"useBlob": true,
"dir": "~/.deepforge/worker/cache"
},
"dir": "~/.deepforge/worker"
},
"mongo": {
"dir": "~/.deepforge/data"
}
+167 -112
Ver Arquivo
@@ -3,15 +3,15 @@
var Command = require('commander').Command,
program = new Command(),
childProcess = require('child_process'),
spawn = childProcess.spawn,
rawSpawn = childProcess.spawn,
Q = require('q'),
execSync = childProcess.execSync,
path = require('path'),
fs = require('fs'),
version = require('../package.json').version,
exists = require('exists-file'),
forever = require('forever-monitor'),
DEFAULT_CONFIG = require('./config.json'),
assign = require('lodash.assign'),
merge = require('lodash.merge'),
config,
configDir = path.join(process.env.HOME, '.deepforge'),
@@ -20,7 +20,12 @@ var Command = require('commander').Command,
localConfig,
rm_rf = require('rimraf'),
p = dir => dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
p = dir => {
if (typeof dir === 'string') {
return dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
}
return dir;
};
// Check for any commands
if (process.argv.length === 2) {
@@ -39,17 +44,17 @@ if (!exists.sync(configPath)) {
}
localConfig = require(configPath);
config = assign(DEFAULT_CONFIG, require(configPath));
config = merge({}, DEFAULT_CONFIG, localConfig);
var getConfigValue = function(id) {
var getConfigValue = function(id, srcConfig) {
var keys = id.split('.'),
value = config;
value = srcConfig || config;
for (var i = 0; i < keys.length; i++) {
value = value[keys[i]];
if (!value) {
if (!value.hasOwnProperty(keys[i])) {
return null;
}
value = value[keys[i]];
}
return value;
};
@@ -59,7 +64,8 @@ var storeConfig = function(id, value) {
var keys = id.split('.').filter(k => k),
lastKey = keys.pop(),
currentObj = localConfig,
current = getConfigValue(id);
current = getConfigValue(id),
expType = typeof getConfigValue(id, DEFAULT_CONFIG);
// Check if it is a valid key
if (current === null) {
@@ -73,25 +79,39 @@ var storeConfig = function(id, value) {
currentObj = currentObj[keys[i]];
}
if (expType !== 'string') {
try { // try to downcast
value = JSON.parse(value);
} catch (e) {
console.log(`Invalid value: "${value}" (expected ${expType})`);
return;
}
}
currentObj[lastKey] = value;
fs.writeFileSync(configPath, JSON.stringify(localConfig, null, 2));
return true;
};
(function() { // Load config to env
var envToConf = require('./envConfig.json');
Object.keys(envToConf).forEach(env => {
var cKey = envToConf[env];
process.env[env] = process.env[env] || p(getConfigValue(cKey));
});
// Special cases
if (process.env.DEEPFORGE_WORKER_USE_BLOB === 'true' &&
exists.sync(process.env.DEEPFORGE_BLOB_DIR)) {
process.env.DEEPFORGE_WORKER_CACHE = process.env.DEEPFORGE_BLOB_DIR + '/wg-content';
}
})();
program
.version('v' + version)
.description('Command line interface for managing deepforge');
// start
var start = function(main, opts) {
var child = new forever.Monitor(main, opts);
child.on('exit', function () {
console.log('Exited after 3 failed restarts');
});
child.start();
};
var isLocalUri = function(protocol, uri) {
return uri.indexOf(protocol + '://localhost') === 0 ||
uri.indexOf(protocol + '://127.0.0.1') === 0;
@@ -115,7 +135,7 @@ var checkMongo = function(args) {
};
var startMongo = function(args, silent) {
var job = spawn('mongod', ['--dbpath', p(config.mongo.dir)], {
var job = rawSpawn('mongod', ['--dbpath', p(config.mongo.dir)], {
cwd: process.env.HOME
});
if (!silent) {
@@ -147,63 +167,95 @@ var startMongo = function(args, silent) {
}
});
};
var checkTorch = function() {
return new Promise(_checkTorch)
.catch(() => 'Torch installation failed');
var hasTorch = function() {
var result = childProcess.spawnSync('th', ['--help']);
return !result.error;
};
var _checkTorch = function(resolve, reject) {
var result = childProcess.spawnSync('th', ['--help']),
tgtDir = p(config.torch.dir),
gcl = `git clone https://github.com/torch/distro.git ${tgtDir} --recursive`;
var installTorchExtras = function() {
// Check if rnn is installed
var result = childProcess.spawnSync('luarocks', ['list', '--porcelain']),
pkgs = result.stdout.toString().split('\n')
.map(line => line.match(/^[a-zA-Z0-9]+/g))
.map(m => m && m[0]);
if (result.error) {
if (pkgs.indexOf('rnn') === -1) {
return spawn('luarocks', ['install', 'rnn']);
} else {
return Q();
}
};
var installTorch = function() {
var tgtDir = p(config.torch.dir),
args;
if (!hasTorch()) {
// Try to install torch
console.log(`Torch7 not found. Installing to ${tgtDir}...`);
args = `clone https://github.com/torch/distro.git ${tgtDir} --recursive`.split(' ');
spawnMany([gcl],
() => {
process.chdir(tgtDir);
spawnMany([
'bash install-deps',
'./install.sh'
], () => {
storeConfig('torch.dir', tgtDir);
resolve(true);
}, reject);
},
reject
);
return spawn('git', args)
.then(code => {
if (code !== 0) {
if (code === 128) {
console.error(`${tgtDir} is not empty. ` +
'Please empty it or change the torch directory:\n' +
'\n deepforge config torch.dir NEW/TORCH/PATH\n');
}
throw `Torch install Failed with exit code ${code}`;
} else { // continue installation
process.chdir(tgtDir);
return spawn('bash', ['install-deps'])
.then(() => spawn('bash', ['install.sh'], true))
.then(() => {
storeConfig('torch.dir', tgtDir);
console.log('Installed torch. Please close and ' +
're-open your terminal to use DeepForge w/ ' +
'torch support!');
process.exit(0);
});
}
});
} else {
resolve(false);
return Q();
}
};
var spawnMany = function(cmds, succ, err) {
var rawCmd,
cmd,
args,
job;
var spawn = function(cmd, args, opts) {
var deferred = Q.defer(),
job,
spawnOpts = typeof opts === 'object' ? opts : null,
forwardStdin = opts === true,
isOpen = true,
err;
if (cmds.length === 0) {
return succ();
}
rawCmd = cmds.shift();
args = rawCmd.split(' ');
cmd = args.shift();
job = spawn(cmd, args);
args = args || [];
job = spawnOpts ? rawSpawn(cmd, args, spawnOpts) : rawSpawn(cmd, args);
job.stdout.on('data', data => process.stdout.write(data));
job.stderr.on('data', data => process.stderr.write(data));
job.on('close', code => {
if (code) {
console.log(`${rawCmd} failed w/ error code ${code}`);
err(code, rawCmd);
isOpen = false;
if (err) {
deferred.reject(err, code);
} else {
spawnMany(cmds, succ, err);
deferred.resolve(code);
}
});
job.on('error', e => err = e);
if (forwardStdin) {
process.stdin.on('data', data => {
if (isOpen) {
job.stdin.write(data);
}
});
}
return deferred.promise;
};
program.command('start')
@@ -213,34 +265,31 @@ program.command('start')
.option('-w, --worker [url]', 'start a worker and connect to given url. Defaults to local deepforge')
.option('-m, --mongo', 'start MongoDB')
.action(args => {
var main = path.join(__dirname, 'start-local.js'),
opts;
opts = {
max: 3,
args: []
};
var main = path.join(__dirname, 'start-local.js');
if (args.port) {
opts.env = {
PORT: args.port
};
process.env.PORT = args.port;
}
if (args.server) {
checkMongo(args);
main = path.join(__dirname, '..', 'app.js');
start(main, opts);
spawn('node', [main]);
}
if (args.worker) {
checkTorch().then(() => {
main = path.join(__dirname, 'start-worker.js');
if (args.worker !== true) {
opts.args.push(args.worker);
}
start(main, opts);
});
if (hasTorch()) {
installTorchExtras().then(() => {
main = path.join(__dirname, 'start-worker.js');
if (args.worker !== true) {
spawn('node', [main, args.worker]);
} else {
spawn('node', [main]);
}
});
} else {
installTorch();
}
}
if (args.mongo) {
@@ -250,7 +299,11 @@ program.command('start')
if (!args.server && !args.worker && !args.mongo) {
// Starting everything
checkMongo(args);
checkTorch().then(() => start(main, opts));
if (hasTorch()) {
installTorchExtras().then(() => spawn('node', [main]));
} else {
installTorch();
}
}
});
@@ -264,7 +317,6 @@ program
.option('-s, --server', 'update deepforge')
.action(args => {
var pkg = 'deepforge',
job,
latestVersion;
// Install the project
@@ -287,38 +339,43 @@ program
}
}
job = spawn('npm', ['install', '-g', pkg]);
job.stdout.on('data', data => process.stdout.write(data.toString()));
job.stderr.on('data', data => process.stderr.write(data.toString()));
job.on('close', code => {
if (!code) {
spawn('npm', ['install', '-g', pkg])
.then(() => {
console.log('Upgrade successful!');
} else {
console.log('Upgrade failed w/ error code: ' + code);
}
});
})
.catch(code => console.log('Upgrade failed w/ error code: ' + code));
}
if (args.torch || !args.server) {
// Update torch
checkTorch().then(justInstalled => {
if (!justInstalled) {
// Upgrade torch
console.log('Upgrading torch...');
job = spawn('bash', ['./update.sh'], {
cwd: p(config.torch.dir)
});
job.stdout.on('data', data => process.stdout.write(data.toString()));
job.stderr.on('data', data => process.stderr.write(data.toString()));
job.on('close', code => {
if (!code) {
console.log('Upgrade successful!');
} else {
console.log('Upgrade failed w/ error code: ' + code);
}
});
if (hasTorch()) {
// Upgrade torch
console.log('Upgrading torch...');
console.log(`Checking for torch in ${config.torch.dir}`);
// Verify that torch is installed in the config's location
if (!exists.sync(path.join(config.torch.dir, 'update.sh'))) {
// config is incorrect!
console.log('Could not find torch installation. Please update the deepforge config with:');
console.log('');
console.log(' deepforge config torch.dir ~/path/to/torch/install');
console.log('');
return;
}
});
spawn('bash', ['./update.sh'], {cwd: p(config.torch.dir)})
.catch(err => console.log('Upgrade failed w/ error code: ' + err.code))
.then(() => {
console.log('About to update rnn package...');
// Update rnn
return spawn('luarocks', ['install', 'rnn']);
})
.then(() => {
console.log('Upgrade successful!');
})
.catch(code => console.log('Upgrade failed w/ error code: ' + code));
} else {
installTorch();
}
}
});
@@ -343,11 +400,9 @@ program
}
if (!opts.torch || opts.clean) { // uninstall deepforge
spawnMany(
['npm uninstall -g deepforge'],
() => console.log('deepforge has been uninstalled!'),
() => console.log('uninstall failed')
);
spawn('npm', ['uninstall', '-g', 'deepforge'])
.then(() => console.log('deepforge has been uninstalled!'))
.catch(() => console.log('uninstall failed'));
}
});
@@ -383,8 +438,8 @@ program
module.exports = function(cmd) {
var cmds = cmd.split(/\s+/).filter(w => !!w);
cmds.unshift('node');
cmds.unshift('./bin/deepforge');
cmds.unshift('node');
program.parse(cmds);
};
+6
Ver Arquivo
@@ -0,0 +1,6 @@
{
"DEEPFORGE_BLOB_DIR": "blob.dir",
"DEEPFORGE_WORKER_CACHE": "worker.cache.dir",
"DEEPFORGE_WORKER_DIR": "worker.dir",
"DEEPFORGE_WORKER_USE_BLOB": "worker.cache.useBlob"
}
+7 -1
Ver Arquivo
@@ -4,7 +4,13 @@ var spawn = require('child_process').spawn,
execJob,
path = require('path'),
env = {cwd: path.join(__dirname, '..')},
workerJob = null;
workerJob = null,
gmeConfig = require(__dirname + '/../config');
// Set the cache to the blob
if (gmeConfig.blob.type === 'FS') {
process.env.DEEPFORGE_WORKER_CACHE = path.resolve(gmeConfig.blob.fsDir + '/wg-content');
}
process.env.NODE_ENV = 'local';
execJob = spawn('npm', [
+36 -2
Ver Arquivo
@@ -4,15 +4,42 @@ var path = require('path'),
fs = require('fs'),
childProcess = require('child_process'),
spawn = childProcess.spawn,
rm_rf = require('rimraf'),
projectConfig = require(__dirname + '/../config'),
executorSrc = path.join(__dirname, '..', 'node_modules', 'webgme', 'src',
'server', 'middleware', 'executor', 'worker'),
workerPath = path.join(__dirname, '..', 'src', 'worker'),
id = Date.now(),
workerRootPath = process.env.DEEPFORGE_WORKER_DIR || path.join(__dirname, '..', 'src', 'worker'),
workerPath = path.join(workerRootPath, `worker_${id}`),
workerConfigPath = path.join(workerPath, 'config.json'),
workerTmp = path.join(workerPath, 'tmp'),
address,
config = {};
var createDir = function(dir) {
try {
fs.statSync(dir);
} catch (e) {
// Create dir
fs.mkdirSync(dir);
return true;
}
return false;
};
createDir(workerRootPath);
createDir(workerPath);
createDir(workerTmp);
// Create sym link to the node_modules
var modules = path.join(workerRootPath, 'node_modules');
try {
fs.statSync(modules);
} catch (e) {
// Create dir
childProcess.spawnSync('ln', ['-s', `${__dirname}/../node_modules`, modules]);
return true;
}
// Check torch support
var result = childProcess.spawnSync('th', ['--help']);
if (result.error) {
@@ -22,7 +49,15 @@ if (result.error) {
process.exit(1);
}
var cleanUp = function() {
console.log('removing worker directory ', workerPath);
rm_rf.sync(workerPath);
};
var startExecutor = function() {
process.on('SIGINT', cleanUp);
process.on('uncaughtException', cleanUp);
// Start the executor
var execJob = spawn('node', [
'node_worker.js',
@@ -42,7 +77,6 @@ var createConfigJson = function() {
}
config[address] = {};
// TODO: Check if the config already exists
fs.writeFile(workerConfigPath, JSON.stringify(config), startExecutor);
};
+2 -1
Ver Arquivo
@@ -12,7 +12,8 @@
"LayerColors": {}
},
"BreadcrumbHeader": {
"pathRule": "history"
"pathRule": "history",
"cachePrefix": "deepforge-header"
},
"FloatingActionButton": {
"hideOnEmpty": true
+5
Ver Arquivo
@@ -9,7 +9,10 @@ require('dotenv').load({silent: true});
// Add/overwrite any additional settings here
config.server.port = +process.env.PORT || config.server.port;
config.mongo.uri = process.env.MONGO_URI || config.mongo.uri;
config.blob.fsDir = process.env.DEEPFORGE_BLOB_DIR || config.blob.fsDir;
config.requirejsPaths.deepforge = './src/common';
config.requirejsPaths.ace = './src/visualizers/widgets/TextEditor/lib/ace';
config.seedProjects.defaultProject = 'project';
config.plugin.allowBrowserExecution = true;
@@ -20,5 +23,7 @@ config.executor.clearOldDataAtStartUp = true;
config.visualization.extraCss.push('deepforge/styles/global.css');
config.storage.autoMerge.enable = true;
validateConfig(config);
module.exports = config;
+1
Ver Arquivo
@@ -20,6 +20,7 @@ config.seedProjects.basePaths.push('src/seeds/pipeline');
config.seedProjects.basePaths.push('src/seeds/devPipelineTests');
config.seedProjects.basePaths.push('src/seeds/project');
config.seedProjects.basePaths.push('src/seeds/cifar10');
config.seedProjects.basePaths.push('src/seeds/xor');
+5 -6
Ver Arquivo
@@ -12,23 +12,22 @@
"watch-test": "./node_modules/nodemon/bin/nodemon.js --exec 'node ./node_modules/mocha/bin/mocha --recursive test'",
"build-nn": "node ./utils/nn-parser.js"
},
"version": "0.10.1",
"version": "0.14.0",
"dependencies": {
"commander": "^2.9.0",
"dotenv": "^2.0.0",
"exists-file": "^2.1.0",
"forever-monitor": "^1.7.0",
"lodash.assign": "^4.0.9",
"lodash.difference": "^4.1.2",
"lodash.merge": "^4.5.1",
"nodemon": "^1.9.2",
"rimraf": "^2.4.0",
"webgme": "^2.0.0",
"webgme-autoviz": "dfst/webgme-autoviz",
"webgme-breadcrumbheader": "^2.1.0",
"webgme-breadcrumbheader": "^2.1.1",
"webgme-chflayout": "^2.0.0",
"webgme-easydag": "dfst/webgme-easydag",
"webgme-fab": "dfst/webgme-fab",
"webgme-simple-nodes": "^2.0.0",
"rimraf": "^2.4.0"
"webgme-simple-nodes": "^2.1.0"
},
"devDependencies": {
"chai": "^3.0.0",
+7 -1
Ver Arquivo
@@ -4,7 +4,13 @@ define({
// DeepForge metadata creation in dist execution
START_CMD: 'deepforge-cmd',
IMAGE: 'IMG',
GRAPH_CREATE: 'GRAPH',
GRAPH_PLOT: 'PLOT',
GRAPH_CREATE_LINE: 'LINE'
GRAPH_CREATE_LINE: 'LINE',
// Code Generation Constants
CTOR_ARGS_ATTR: 'ctor_arg_order'
});
+380
Ver Arquivo
@@ -0,0 +1,380 @@
/* globals define*/
(function(root, factory){
if(typeof define === 'function' && define.amd) {
define(['./lua'], function(luajs){
return (root.LayerParser = factory(luajs));
});
} else if(typeof module === 'object' && module.exports) {
var luajs = require('./lua');
module.exports = (root.LayerParser = factory(luajs));
}
}(this, function(luajs) {
var LayerParser = {};
//////////////////////// Setters ////////////////////////
var returnsSelf = function(fnNode){
var stats = fnNode.block.stats,
last = stats[stats.length-1];
if (last.type === 'stat.return') {
return last.nret[0].type === 'variable' && last.nret[0].val === 'self';
}
return false;
};
var isAttrSetter = function(node){
if (node.type === 'stat.assignment' && node.lefts.length === 1) {
var left = node.lefts[0];
return left.type === 'expr.index' && left.self.val === 'self';
}
return false;
};
var getSettingAttrName = function(node){
if (isAttrSetter(node)) {
var left = node.lefts[0];
return left.key.val;
}
return null;
};
var getSettingAttrValue = function(node){
if (isAttrSetter(node)) {
return node.right;
}
return null;
};
var isSetterMethod = function(curr, parent, className){
if (parent && parent.type === 'stat.method') {
// is it a fn w/ two statements (stats)
if (parent.self.val === className && curr.type === 'function' &&
curr.block.stats.length === 2) {
// Is the first statement setting a value?
return returnsSelf(curr) && getSettingAttrName(curr.block.stats[0]); // does it return itself?
}
}
return false;
};
var isFnArg = function(method, name) {
return method.args.indexOf(name) !== -1;
};
var getSetterSchema = function(node, method) {
var setterType,
setterFn,
value = getSettingAttrValue(node);
if (value[0].type === 'variable' && isFnArg(method.func, value[0].val)) {
setterType = 'arg';
setterFn = method.key.val;
} else {
setterType = 'const';
setterFn = {};
setterFn[value[0].val] = method.key.val;
}
return {
setterType,
setterFn
};
};
//////////////////////// Setters END ////////////////////////
var isInitFn = function(node, className) {
if (node.type === 'stat.method' && node.self.val === className) {
return node.key.val === '__init';
}
return false;
};
var getClassAttrDefs = function(method) {
var fn = method.func,
dict = {},
attr,
right,
value;
luajs.codegen.traverse(curr => {
if (isAttrSetter(curr)) {
// Store the value if it is set to a constant
attr = curr.lefts[0].key.val;
right = curr.right[0];
if (right.type.indexOf('const.') !== -1) {
value = right.val;
if (right.type === 'const.nil') {
value = null;
}
dict[attr] = value;
}
}
})(fn);
return dict;
};
var getAttrsAndVals = function(method) {
// Given a method, get the 'self' attributes and the default values
var fn = method.func,
dict = {},
varName,
value,
varUsageCnt = {};
// Get the variables that are used only once (or updating themselves)
luajs.codegen.traverse(curr => {
if (curr.type === 'variable') {
varUsageCnt[curr.val] = varUsageCnt[curr.val] ?
varUsageCnt[curr.val] + 1 : 1;
}
})(method);
luajs.codegen.traverse(curr => {
// If the variable is only used once and is 'or'-ed w/ a constant
// during this use, we can infer that this is the default value
if (curr.type === 'expr.op' && curr.op === 'op.or' &&
curr.left.type === 'variable' && curr.right.type.indexOf('const') !== -1) {
varName = curr.left.val;
if (varUsageCnt[varName] === 1) {
value = curr.right.type === 'const.nil' ? null : curr.right;
dict[varName] = value;
}
}
})(fn);
return dict;
};
var copyNodeValues = function(attrs, from, to) {
var value;
for (var i = attrs.length; i--;) {
value = from[attrs[i]] || null;
if (value) {
value = (value && value.hasOwnProperty('val')) ? value.val : value;
to[attrs[i]] = value;
}
}
return to;
};
var getTypeCheckInfo = function(cond) {
var caller,
method,
target,
expType;
// Check for torch.isTypeOf:
if (cond.type === 'expr.call' && cond.func.type === 'expr.index') {
caller = cond.func.self.val;
method = cond.func.key.val;
if (cond.type === 'expr.call' && caller === 'torch') {
target = cond.args[0].val;
if (method === 'isTypeOf' && target) {
expType = cond.args[1].val;
return {
target,
type: expType
};
}
}
} else if (cond.type === 'expr.op') { // torch.type() === ''
// Check right side, too!
var sides = [cond.left, cond.right],
side,
otherSide;
for (var i = sides.length; i--;) {
side = sides[i];
otherSide = sides[(i+1)%2];
if (side.type === 'expr.call' && side.func.type === 'expr.index') {
// Is it torch?
caller = side.func.self.val;
method = side.func.key.val;
if (caller === 'torch' && method === 'type') {
if (side.args[0].type === 'variable') {
target = side.args[0].val;
if (otherSide.type === 'const.string') {
expType = otherSide.val;
return {
target: target,
type: expType
};
}
}
}
}
}
return null;
}
};
var isError = function(stat) {
var fn;
if (stat.type === 'stat.expr' && stat.expr.type === 'expr.call') {
fn = stat.expr.func.val;
return fn === 'error';
}
return false;
};
var inferParamTypes = function(node, paramDefs) {
var types = {},
check,
cond;
// Infer from assertions
luajs.codegen.traverse(curr => {
// check for 'assert's that check type
if (curr.type === 'expr.call' && curr.func.val === 'assert') {
cond = curr.args[0];
check = getTypeCheckInfo(cond);
if (check) {
types[check.target] = check.type;
}
} else if (curr.type === 'stat.if' && curr.cond.op === 'uop.not') {
// if statements throwing errors on type mismatch
cond = curr.cond.operand; // non-negated version
// Check that it throws an error on true
if (curr.tblock.stats.some(isError)) {
check = getTypeCheckInfo(cond);
if (check) {
types[check.target] = check.type;
}
}
}
})(node);
// Infer from defaults
Object.keys(paramDefs).forEach(param => {
var val = paramDefs[param];
if (val) { // initialized to 'null' doesn't help us...
types[param] = val.type.replace('const.', '');
}
});
return types;
};
var findTorchClass = function(ast){
var torchClassArgs, // args for `torch.class(...)`
name = '',
baseType,
params,
setters = {},
defaults = {},
paramDefs,
attrDefs;
if(ast.type == 'function'){
ast.block.stats.forEach(function(func){
if(func.type == 'stat.local' && func.right && func.right[0] &&
func.right[0].func && func.right[0].func.self &&
func.right[0].func.self.val == 'torch' &&
func.right[0].func.key.val == 'class'){
torchClassArgs = func.right[0].args.map(arg => arg.val);
name = torchClassArgs[0];
if(name !== ''){
name = name.replace('nn.', '');
if (torchClassArgs.length > 1) {
baseType = torchClassArgs[1].replace('nn.', '');
}
}
}
});
}
// Get the setters, defaults and type info (inferred)
var setterNames,
schema,
types,
values;
luajs.codegen.traverse((curr, parent) => {
var firstLine,
attrName;
// Record the setter functions
if (isSetterMethod(curr, parent, name)) {
firstLine = curr.block.stats[0];
// just use the attribute attrName for now...
attrName = getSettingAttrName(firstLine);
// merge schemas
schema = getSetterSchema(firstLine, parent);
if (setters[attrName] && setters[attrName].setterType === 'const') { // merge
for (var val in schema.setterFn) {
setters[attrName].setterFn[val] = schema.setterFn[val];
}
} else {
setters[attrName] = schema;
}
} else if (isInitFn(curr, name)) { // Record the defaults
paramDefs = getAttrsAndVals(curr);
attrDefs = getClassAttrDefs(curr);
types = inferParamTypes(curr, paramDefs);
// get ctor args
params = curr.func.args;
if(params.length === 0 && curr.func.varargs){
params.push('params');
}
}
})(ast);
// Get the defaults for the params from defs
if (paramDefs && params) {
copyNodeValues(params, paramDefs, defaults);
}
// Get the defaults for the setters from attrDefs
if (attrDefs) {
setterNames = Object.keys(setters);
copyNodeValues(setterNames, attrDefs, defaults);
}
// Remove any const setters w/ only one value and no default
setterNames = Object.keys(setters);
for (var i = setterNames.length; i--;) {
schema = setters[setterNames[i]];
if (schema.setterType === 'const') {
values = Object.keys(schema.setterFn);
if (values.length === 1 &&
// boolean setters can have the default value inferred
values[0] !== 'true' && values[0] !== 'false' &&
!defaults[setterNames[i]]) {
delete setters[setterNames[i]];
}
}
}
return {
name,
baseType,
params,
setters,
types,
defaults
};
};
LayerParser.parse = function(text) {
try {
var ast = luajs.parser.parse(text);
return findTorchClass(ast);
} catch (e) {
return null;
}
};
return LayerParser;
}));
+54 -23
Ver Arquivo
@@ -1,13 +1,17 @@
/* globals Materialize, WebGMEGlobal, define*/
/* globals WebGMEGlobal, define*/
// This file creates the DeepForge namespace and defines basic actions
define([
'panel/FloatingActionButton/styles/Materialize',
'js/RegistryKeys',
'js/Panels/MetaEditor/MetaEditorConstants',
'js/Constants'
'js/Constants',
'q'
], function(
Materialize,
REGISTRY_KEYS,
META_CONSTANTS,
CONSTANTS
CONSTANTS,
Q
) {
var DeepForge = {},
placesTerritoryId,
@@ -90,6 +94,7 @@ define([
};
//////////////////// DeepForge places detection ////////////////////
DeepForge.places = {};
var TYPE_TO_CONTAINER = {
Architecture: 'MyArchitectures',
@@ -105,10 +110,29 @@ define([
PLACE_NAMES = Object.keys(TYPE_TO_CONTAINER).map(key => TYPE_TO_CONTAINER[key]);
// Add DeepForge directories
var placePromises = {},
setPlaceId = {},
firstProject = true;
var getPlace = function(name) {
return placePromises[name];
};
var initializePlaces = function() {
PLACE_NAMES.forEach(name => {
var deferred = Q.defer();
placePromises[name] = deferred.promise;
setPlaceId[name] = deferred.resolve;
});
};
var updateDeepForgeNamespace = function() {
var territory = {};
DeepForge.places = {};
if (!firstProject) {
initializePlaces();
}
firstProject = false;
// Create a territory
if (placesTerritoryId) {
@@ -135,13 +159,16 @@ define([
nodes.forEach(node =>
nodeIdsByName[node.getAttribute('name')] = node.getId());
PLACE_NAMES.forEach(name => DeepForge.places[name] = nodeIdsByName[name]);
PLACE_NAMES.forEach(name => setPlaceId[name](nodeIdsByName[name]));
// Remove the territory
client.removeUI(placesTerritoryId);
placesTerritoryId = null;
};
initializePlaces();
PLACE_NAMES.forEach(name => DeepForge.places[name] = getPlace.bind(null, name));
//////////////////// DeepForge creation actions ////////////////////
var instances = [
'Architecture',
@@ -154,8 +181,7 @@ define([
];
var createNew = function(type, metasheetName) {
var parentId,
placeName = TYPE_TO_CONTAINER[type],
var placeName = TYPE_TO_CONTAINER[type],
newId,
baseId,
msg = `Created new ${type + (metasheetName ? ' prototype' : '')}`;
@@ -165,19 +191,20 @@ define([
.getId();
// Look up the parent container
parentId = DeepForge.places[placeName];
DeepForge.places[placeName]().then(parentId => {
client.startTransaction(msg);
newId = createNamedNode(baseId, parentId, !!metasheetName);
client.startTransaction(msg);
newId = createNamedNode(baseId, parentId, !!metasheetName);
if (metasheetName) {
addToMetaSheet(newId, metasheetName);
}
if (metasheetName) {
addToMetaSheet(newId, metasheetName);
}
client.completeTransaction();
client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(newId);
return newId;
WebGMEGlobal.State.registerActiveObject(newId);
return newId;
});
};
var createCustomLayer = function(typeName) {
@@ -198,16 +225,20 @@ define([
}
}
client.startTransaction(msg);
return DeepForge.places.MyLayers()
.then(id => {
newId = createNamedNode(baseId, DeepForge.places.MyLayers, true);
addToMetaSheet(newId, 'CustomLayers');
client.addMixin(newId, customLayerId);
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
client.startTransaction(msg);
client.completeTransaction();
newId = createNamedNode(baseId, id, true);
addToMetaSheet(newId, 'CustomLayers');
client.addMixin(newId, customLayerId);
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
WebGMEGlobal.State.registerActiveObject(newId);
client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(newId);
});
};
// Creating Artifacts
+30 -11
Ver Arquivo
@@ -1,6 +1,8 @@
/* globals define*/
define([
'deepforge/Constants'
], function(
Constants
) {
'use strict';
@@ -15,32 +17,49 @@ define([
return result;
};
var isArgument = function(arg) {
return arg.hasOwnProperty('argindex');
};
var sortByIndex = function(a, b) {
return a.argindex > b.argindex;
var isSetter = function(arg) {
return arg.hasOwnProperty('setterType');
};
var createLayerDict = function(core, meta) {
var node,
names = Object.keys(meta),
layers = {};
layers = {},
setters,
ctorData,
ctorArgs,
attrs;
for (var i = names.length; i--;) {
node = meta[names[i]];
layers[names[i]] = core.getValidAttributeNames(node)
ctorData = core.getAttribute(node, Constants.CTOR_ARGS_ATTR);
attrs = core.getValidAttributeNames(node);
layers[names[i]] = {};
if (ctorData) {
ctorArgs = ctorData.split(',')
.map(attr => prepAttribute(core, node, attr));
// Get the constructor args
layers[names[i]].args = ctorArgs;
} else {
layers[names[i]].args = [];
}
layers[names[i]].setters = {};
setters = attrs
.map(attr => prepAttribute(core, node, attr))
.filter(isArgument)
.sort(sortByIndex);
.filter(isSetter);
for (var j = setters.length; j--;) {
layers[names[i]].setters[setters[j].name] = setters[j];
}
}
return layers;
};
// When provided with the META, create the given LayerDict object
// - Sort (and filter) by argindex
// - Filter out the ctor args (in order)
// - add name attribute to schema
// - store this array under the META name
-546
Ver Arquivo
@@ -1,546 +0,0 @@
# This file should actually be an alternative way of viewing the metamodel.
#
# This contains metadata about the Torch nn library used for
# creating the metamodel
#
# By default...
# - all attributes are a number
# - default values are optional
# - all booleans default to false
# - list attributes are specified with WORD...WORD
# - if `ignore` is set, the attribute is not added to the metamodel
# This should have tests to verify that this document is up to date...
# TODO
Containers:
- Concat:
- dim:
min: 1 # TODO: Figure out exactly how this works
Module:
- SpatialBatchNormalization:
- input:
infer: dimensionality # change this to `infer: 'dimensionality'`
- eps:
default: 0.00001
- momentum:
default: 0.1
- affine:
default: true
- BatchNormalization:
- input:
infer: dimensionality # change this to `infer: 'dimensionality'`
- eps:
default: 0.00001
- momentum:
default: 0.1
- affine:
default: true
- Threshold:
- threshold:
type: float
default: 1e-6
- value:
type: float
default: 0
- inplace:
type: boolean
default: false
ConvLayer:
- TemporalConvolution:
- inputFrameSize:
min: 1
- outputFrameSize:
min: 1
- kernelWidth:
min: 1
- step:
default: 1
- TemporalMaxPooling:
- kernelWidth:
min: 1
- step: # FIXME: defaults to 'kernelWidth'
min: 1
- TemporalSubSampling:
- inputFrameSize:
min: 1
- kernelWidth:
min: 1
- step:
min: 1
# TODO: What is the default?
- LookupTable:
- nIndex:
min: 1
- sizes:
min: 1
# Spatial Modules
- SpatialConvolutionMM:
- nInputPlane: # TODO: Infer this
min: 1
- nOutputPlane:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- padWidth:
min: 0
default: 0
- padHeight: # FIXME: this defaults to padWidth - not 0
min: 0
default: 0
- SpatialConvolution:
- nInputPlane:
min: 1
- nOutputPlane:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialConvolutionMap:
- connectionMatrix:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialLPPooling:
- nInputPlane:
min: 1
- norm:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialMaxPooling:
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialAveragePooling:
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialAdaptiveMaxPooling: # output is width x height
- width:
min: 1
- height:
min: 1
- SpatialSubSampling:
- nInputPlane:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- SpatialUpSamplingNearest:
- scale: # upscale ratio
min: 1
- SpatialZeroPadding:
- left:
min: 0
- right:
min: 0
- top:
min: 0
- bottom:
min: 0
- SpatialSubtractiveNormalization:
- nInputPlane:
min: 1
- kernel:
min: 1
- SpatialCrossMapLRN:
- size:
min: 1
- alpha:
default: 0.0001
- beta:
default: 0.75
- k:
default: 1
- SpatialConvolutionLocal:
- nInputPlane:
min: 1
- nOutputPlane:
min: 1
- inputWidth: # TODO: infer this
min: 1
- inputHeight: # TODO: infer this
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- padWidth:
min: 0
default: 0
- padHeight: # FIXME: this defaults to padWidth - not 0
min: 0
default: 0
- SpatialDropout:
- probability:
default: 0.5
- SpatialFractionalMaxPooling:
- poolWidth:
- min: 2
- poolHeight:
- min: 2
- outWidth: # Optionally, these could be ratioW/H FIXME
- min: 1
- outHeight:
- min: 1
- SpatialDivisiveNormalization:
- nInputPlane: # TODO: infer this
- default: 1
- kernel: # TODO: this is a tensor type...
- threshold:
- default: 0.0001
- thresval:
- default: 0.0001 # FIXME: this defaults to "threshold"
- SpatialContrastiveNormalization:
- nInputPlane: # TODO: infer this
- default: 1
- kernel: # TODO: this is a tensor type...
- threshold:
- default: 0.0001
- thresval:
- default: 0.0001 # FIXME: this defaults to "threshold"
- SpatialFullConvolution:
- nInputPlane: # TODO: should infer this
min: 1
- nOutputPlane:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- padWidth:
min: 0
default: 0
- padHeight:
min: 0
default: 0
- adjWidth:
min: 0
default: 0
- adjHeight:
min: 0
default: 0
# Additional constraint:
# Volumetric Modules
- VolumetricConvolution:
- nInputPlane:
min: 1
- nOutputPlane:
min: 1
- kernelTime:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideTime:
min: 1
default: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
- VolumetricMaxPooling:
- kernelTime:
min: 1
- kernelWidth:
min: 1
- kernelHeight:
min: 1
- strideTime:
min: 1
default: 1
- strideWidth:
min: 1
default: 1
- strideHeight:
min: 1
default: 1
SimpleLayer:
- Linear: # FIXME: These should contain the actual args
- input:
infer: dimensionality
- output:
min: 1
- SparseLinear:
- input:
infer: dimensionality
- output:
min: 1
- Dropout:
- probability:
type: float
- Abs:
- Add:
- isScalar:
type: boolean
- Mul:
- CMul:
- size: null
- Max:
- dimension:
min: 0
- Min:
- dimension:
min: 0
- Mean:
- dimension:
min: 0
- Sum:
- dimension:
min: 0
- Euclidean:
- output:
min: 0
- WeightedEuclidean:
- output:
min: 0
- Identity:
- Copy: # Casts types
- inputType:
type: string
- outputType:
type: string
- forceCopy:
type: boolean
- Narrow:
- dimension:
min: 0
- offset:
min: 0
- length:
min: 0
- Replicate:
- nFeature:
min: 0
- Reshape:
- dimensions:
type: list
- View:
- sizes: # list
type: list
min: 0
- Select:
- dimensions:
type: list
- Exp
- Square
- Sqrt
- Power:
- p: null
- MM:
- transA:
type: boolean
- transB:
type: boolean
TransferLayer:
- HardTanh
- HardShrink:
- lambda:
type: float
- SoftShrink:
- lambda:
type: float
- SoftMax
- SoftMin
- SoftPlus
- SoftSign # Typo in the docs on this one
- LogSigmoid
- LogSoftMax # Also in Criterion?
- Sigmoid
- Tanh
- ReLU
- PReLU # Missing from docs
- RReLU # Missing from docs
- LeakyReLU # Missing from docs
- AddConstant:
- scalar:
type: float
- MulConstant:
- scalar:
type: float
min: 1
- inplace:
default: false
Criterion:
- BCECriterion
- WeightedMSECriterion
- SmoothL1Criterion
- MSECriterion
- AbsCriterion
- MultiCriterion
- DistKLDivCriterion
- HingeEmbeddingCriterion
- CriterionTable
- MultiMarginCriterion
- MultiLabelMarginCriterion
- L1HingeEmbeddingCriterion
- CosineEmbeddingCriterion
- MarginRankingCriterion
- CrossEntropyCriterion
- MarginCriterion
- ClassNLLCriterion
- ParallelCriterion
MiscLayers:
- Jacobian
- ConcatTable
- CMulTable
- CAddTable
- TanhShrink
- Padding:
- dim:
- pad:
min: 0
- nInputDim: # TODO: infer?
min: 1
- value:
min: 0
default: 0
# TODO: Add the following layers
#VolumetricMaxUnpooling
# Takes a poolingModule as an arg...
#MixtureTable
#NarrowTable
#SplitTable
#DotProduct
#DepthConcat
#Parallel
#Log
#hessian
#ELU
#CSubTable
#VolumetricAveragePooling
#StochasticGradient
#Bilinear
#VolumetricFullConvolution
#SparseJacobian
#Contiguous
#L1Cost
#JoinTable
#CosineDistance
#Index
#L1Penalty
#Cosine
#Clamp
#SpatialConvolutionMM
#LogSigmoid
#ParallelTable
#CDivTable
#SpatialFullConvolutionMap
#GradientReversal
#SpatialMaxUnpooling
#Transpose
#Normalize
#SpatialSoftMax
#SelectTable
#FlattenTable
# CONTAINERS and TableLayouts
# Some of these are captured by the visual structure of the architecture and are not needed
# as explicit layers in the metamodel
#TableLayer:
#- ConcatTable
#Container:
+30 -8
Ver Arquivo
@@ -106,21 +106,30 @@ define([
};
LocalExecutor.prototype.Save = function(node) {
var nodeId = this.core.getPath(node),
parentNode;
var parentNode,
currNameHashPairs;
// Get the input node
this.logger.info('Calling save operation!');
return this._getSaveDir()
.then(_saveDir => {
parentNode = _saveDir;
return this.core.loadChildren(_saveDir);
})
.then(artifacts => {
currNameHashPairs = artifacts
.map(node => [
this.core.getAttribute(node, 'name'),
this.core.getAttribute(node, 'data')
]);
return this.getInputs(node);
})
.then(inputs => {
var ids = inputs.map(i => this.core.getPath(i[2])),
allDataNodes,
dataNodes;
dataNodes = Object.keys(this.nodes)
allDataNodes = Object.keys(this.nodes)
.map(id => this.nodes[id])
.filter(node => this.isMetaTypeOf(node, this.META.Transporter))
.filter(node =>
@@ -129,10 +138,18 @@ define([
.map(node => this.core.getPointerPath(node, 'src'))
.map(id => this.nodes[id]);
// Remove nodes that already exist
dataNodes = allDataNodes.filter(dataNode => {
var hash = this.core.getAttribute(dataNode, 'data'),
name = this.core.getOwnAttribute(node, 'saveName') ||
this.core.getAttribute(dataNode, 'name');
return !(currNameHashPairs
.find(pair => pair[0] === name && pair[1] === hash));
});
// get the input node
if (dataNodes.length === 0) {
this.logger.error(`Could not find data to save! ${nodeId}`);
} else {
if (dataNodes.length !== 0) {
var newNodes = this.core.copyNodes(dataNodes, parentNode),
newName = this.core.getOwnAttribute(node, 'saveName');
if (newName) {
@@ -140,9 +157,14 @@ define([
this.core.setAttribute(node, 'name', newName)
);
}
var hashes = dataNodes.map(n => this.core.getAttribute(n, 'data'));
this.logger.info(`saving hashes: ${hashes.map(h => `"${h}"`)}`);
} else if (allDataNodes.length === 0) {
this.logger.warn('No data nodes found!');
} else {
this.logger.info('Using cached artifact(s)');
}
var hashes = dataNodes.map(n => this.core.getAttribute(n, 'data'));
this.logger.info(`saving hashes: ${hashes.map(h => `"${h}"`)}`);
this.onOperationComplete(node);
});
};
+54 -19
Ver Arquivo
@@ -1,7 +1,9 @@
/*globals define, WebGMEGlobal*/
/*globals define, requirejs*/
define([
'plugin/util',
'q'
], function(
PluginUtils,
Q
) {
var PtrCodeGen = function() {
@@ -14,34 +16,67 @@ define([
var metanode = this.core.getMetaType(ptrNode),
pluginId;
this.logger.debug(`loaded pointer target of ${ptrId}: ${ptrNode}`);
pluginId = this.core.getRegistry(ptrNode, 'validPlugins').split(' ').shift();
this.logger.info(`generating code for ${this.core.getAttribute(ptrNode, 'name')} using ${pluginId}`);
var context = WebGMEGlobal.Client.getCurrentPluginContext(pluginId);
context.managerConfig.namespace = this.core.getNamespace(metanode);
context.managerConfig.activeNode = this.core.getPath(ptrNode);
var context = {
namespace: this.core.getNamespace(metanode),
activeNode: this.core.getPath(ptrNode)
};
// Load and run the plugin
return Q.nfcall(this.executePlugin.bind(this), pluginId, context);
return this.executePlugin(pluginId, context);
})
.then(hashes => hashes[0]); // Grab the first asset for now
};
PtrCodeGen.prototype.executePlugin = function(pluginId, config, callback) {
// Call the Interpreter manager in a Q.ninvoke friendly way
// I need to create a custom context for the given plugin:
// - Set the activeNode to the given referenced node
// - If the activeNode is namespaced, set META to the given namespace
//
// FIXME: Check if it is running in the browser or on the server
WebGMEGlobal.Client.runBrowserPlugin(pluginId, config, (err, result) => {
if (!result.success) {
return callback(result.getError());
}
this.logger.info('Finished calling ' + pluginId);
callback(null, result.artifacts);
PtrCodeGen.prototype.createPlugin = function(pluginId) {
var deferred = Q.defer(),
pluginPath = [
'plugin',
pluginId,
pluginId,
pluginId
].join('/');
requirejs([pluginPath], Plugin => {
var plugin = new Plugin();
deferred.resolve(plugin);
}, err => {
this.logger.error(`Could not load ${pluginId}: ${err}`);
deferred.reject(err);
});
return deferred.promise;
};
PtrCodeGen.prototype.configurePlugin = function(plugin, opts) {
var logger = this.logger.fork(plugin.getName());
return PluginUtils.loadNodesAtCommitHash(
this.project,
this.core,
this.commitHash,
this.logger,
opts
).then(config => {
plugin.initialize(logger, this.blobClient, this.gmeConfig);
config.core = this.core;
plugin.configure(config);
return plugin;
});
};
PtrCodeGen.prototype.executePlugin = function(pluginId, config) {
return this.createPlugin(pluginId)
.then(plugin => this.configurePlugin(plugin, config))
.then(plugin => {
return Q.ninvoke(plugin, 'main');
})
.then(result => {
this.logger.info('Finished calling ' + pluginId);
return result.artifacts;
});
};
return PtrCodeGen;
+4
Ver Arquivo
@@ -22,3 +22,7 @@
.create-node text {
font-style: italic;
}
.job-canceled {
background-color: #ffe0b2;
}
+58
Ver Arquivo
@@ -0,0 +1,58 @@
/* globals define*/
define([
], function(
) {
var isBoolean = txt => {
return typeof txt === 'boolean' || (txt === 'false' || txt === 'true');
};
var getSetterSchema = function(name, setters, defaults) {
var values,
schema = setters[name];
if (defaults.hasOwnProperty(name)) {
schema.default = defaults[name];
}
schema.type = 'string';
if (schema.setterType === 'const') {
values = Object.keys(schema.setterFn);
schema.isEnum = true;
schema.enumValues = values;
if (values.every(isBoolean)) {
if (!defaults.hasOwnProperty(name) && values.length === 1) {
// there is only a method to toggle the flag to true/false,
// then the default must be the other one
schema.default = values[0] === 'true' ? false : true;
}
if (isBoolean(schema.default)) {
schema.type = 'boolean';
}
}
}
return schema;
};
var abbrWord = function(word) { // camelcase
word = word.substring(0, 1).toUpperCase() + word.substring(1);
return word.split(/[a-z]+/g).join('').toLowerCase();
};
var abbrPhrase = function(words) { // dashes, spaces, underscores, etc
return words.map(word => word[0]).join('');
};
var abbr = function(phrase) {
var words = phrase.split(/[^a-zA-Z0-9]+/g);
if (words.length === 1) {
return abbrWord(phrase);
} else {
return abbrPhrase(words);
}
};
return {
getSetterSchema: getSetterSchema,
abbr: abbr
};
});
+102
Ver Arquivo
@@ -0,0 +1,102 @@
/* globals define, WebGMEGlobal */
// Mixin for executing jobs and pipelines
define([
'executor/ExecutorClient',
'panel/FloatingActionButton/styles/Materialize'
], function(
ExecutorClient,
Materialize
) {
var Execute = function(client, logger) {
this.client = this.client || client;
this.logger = this.logger || logger;
this._executor = new ExecutorClient({
logger: this.logger.fork('ExecutorClient'),
serverPort: WebGMEGlobal.gmeConfig.server.port,
httpsecure: window.location.protocol === 'https:'
});
};
Execute.prototype.executeJob = function(node) {
return this.runExecutionPlugin('ExecuteJob', {node: node});
};
Execute.prototype.executePipeline = function(node) {
return this.runExecutionPlugin('ExecutePipeline', {node: node});
};
Execute.prototype.runExecutionPlugin = function(pluginId, opts) {
var context = this.client.getCurrentPluginContext(pluginId),
node = opts.node || this.client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
method;
// Set the activeNode
context.managerConfig.namespace = 'pipeline';
context.managerConfig.activeNode = node.getId();
method = opts.useSecondary ? 'runBrowserPlugin' : 'runServerPlugin';
this.client[method](pluginId, context, (err, result) => {
var msg = err ? `${name} failed!` : `${name} executed successfully!`,
duration = err ? 4000 : 2000;
// Check if it was canceled - if so, show that type of message
if (result) {
msg = result.messages[0].message;
duration = 4000;
}
Materialize.toast(msg, duration);
});
};
Execute.prototype.isRunning = function(node) {
var baseId,
base,
type;
node = node || this.client.getNode(this._currentNodeId);
baseId = node.getBaseId();
base = this.client.getNode(baseId);
type = base.getAttribute('name');
if (type === 'Execution') {
return node.getAttribute('status') === 'running';
} else if (type === 'Job') {
return this.isRunningJob(node);
}
return false;
};
Execute.prototype.isRunningJob = function(job) {
var status = job.getAttribute('status');
return (status === 'running' || status === 'pending') &&
job.getAttribute('secret') && job.getAttribute('jobId');
};
Execute.prototype.stopJob = function(job) {
var jobHash,
jobId,
secret;
job = job || this.client.getNode(this._currentNodeId);
jobId = job.getId();
jobHash = job.getAttribute('jobId');
secret = job.getAttribute('secret');
if (!jobHash || !secret) {
this.logger.error('Cannot stop job. Missing jobHash or secret');
return;
}
this.client.delAttributes(jobId, 'jobId');
this.client.delAttributes(jobId, 'secret');
this.client.setAttributes(jobId, 'status', 'canceled');
return this._executor.cancelJob(jobHash, secret)
.then(() => this.logger.info(`${jobHash} has been cancelled!`))
.fail(err => this.logger.error(`Job cancel failed: ${err}`));
};
return Execute;
});
+1 -1
Ver Arquivo
@@ -21,7 +21,7 @@ define([
RenameablePanel.OPTIONS = PanelBaseWithHeader.OPTIONS;
RenameablePanel.prototype.initializeRenameable = function () {
this.$panelHeaderTitle.on('dblclick', this.editTitle.bind(this));
this.$panelHeaderTitle.on('click', this.editTitle.bind(this));
};
RenameablePanel.prototype.currentNodeId = function () {
+19
Ver Arquivo
@@ -0,0 +1,19 @@
/* globals define*/
define({
getDisplayTime: timestamp => {
var today = new Date().toLocaleDateString(),
date = new Date(timestamp).toLocaleDateString();
if (date === today) {
date = `Today (${new Date(timestamp).toLocaleTimeString()})`;
}
return date;
},
ClassForJobStatus: {
success: 'success',
canceled: 'job-canceled',
failed: 'danger',
pending: '',
running: 'warning'
}
});
@@ -0,0 +1,17 @@
/*globals define*/
define([
'decorators/EllipseDecorator/EasyDAG/AttributeField'
], function(
BaseAttributeField
) {
var AttributeField = function() {
BaseAttributeField.apply(this, arguments);
};
AttributeField.prototype = Object.create(BaseAttributeField.prototype);
AttributeField.prototype.onClick = function() {
};
return AttributeField;
});
@@ -1,15 +1,15 @@
/*globals define, _*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'./PointerField.RO',
'./AttributeField.RO',
'css!./JobDecorator.EasyDAGWidget.css'
], function (
EllipseDecorator
EllipseDecorator,
PointerField,
AttributeField
) {
'use strict';
@@ -20,6 +20,7 @@ define([
pending: '#9e9e9e',
queued: '#cfd8dc',
running: '#fff59d',
canceled: '#ffcc80',
success: '#66bb6a',
fail: '#e57373'
};
@@ -35,6 +36,8 @@ define([
status: true,
execFiles: true,
stdout: true,
secret: true,
jobId: true,
debug: true
};
EllipseDecorator.call(this, options);
@@ -43,18 +46,46 @@ define([
_.extend(JobDecorator.prototype, EllipseDecorator.prototype);
JobDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
JobDecorator.prototype.AttributeField = AttributeField;
JobDecorator.prototype.PointerField = PointerField;
JobDecorator.prototype.isArtifactLoader = function() {
return this._node.name === 'ArtifactLoader';
};
JobDecorator.prototype.getDisplayName = function() {
if (this.isArtifactLoader()) {
var id = this._node.pointers.artifact;
// Try to look up the pointer name
return this.nameFor[id] || this._node.name;
}
return this._node.name;
};
JobDecorator.prototype.setAttributes = function() {
EllipseDecorator.prototype.setAttributes.call(this);
var attrs = this._node.attributes,
status = attrs.status && attrs.status.value;
status = attrs.status && attrs.status.value,
opAttrs = Object.keys(this._node.opAttributes);
// Update the color based on the 'status' attr
this.color = COLORS[status] || COLORS.fail;
// Set _attributes from opAttributes
for (var i = opAttrs.length; i--;) {
this._attributes[opAttrs[i]] = this._node.opAttributes[opAttrs[i]];
}
};
JobDecorator.prototype.updateTargetName = function() {
EllipseDecorator.prototype.updateTargetName.apply(this, arguments);
var name = this.getDisplayName();
if (name !== this.name) {
this.name = name;
this.onResize();
}
};
return JobDecorator;
@@ -0,0 +1,22 @@
/*globals define*/
define([
'decorators/EllipseDecorator/EasyDAG/PointerField'
], function(
BasePointerField
) {
var PointerField = function() {
BasePointerField.apply(this, arguments);
};
PointerField.prototype = Object.create(BasePointerField.prototype);
PointerField.prototype.onClick = function() {
};
// Remove the delete icon and adjust the text location
PointerField.prototype.hasIcon = function() {
return false;
};
return PointerField;
});
@@ -0,0 +1,110 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true, camelcase: false*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'deepforge/Constants',
'./LayerField'
], function (
EllipseDecorator,
Constants,
LayerField
) {
'use strict';
var LayerDecorator,
DECORATOR_ID = 'LayerDecorator';
// Layer nodes need to be able to...
// - show their ports
// - highlight ports
// - unhighlight ports
// - report the location of specific ports
LayerDecorator = function (options) {
options.skipAttributes = {name: true};
options.skipAttributes[Constants.CTOR_ARGS_ATTR] = true;
EllipseDecorator.call(this, options);
};
_.extend(LayerDecorator.prototype, EllipseDecorator.prototype);
LayerDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
LayerDecorator.prototype.PointerField = LayerField;
LayerDecorator.prototype.getDisplayName = function() {
return this._node.name;
};
// Create the pointer fields and change the event handlers
LayerDecorator.prototype.createPointerFields = function() {
var i = this.fields.length,
y,
ptr;
// Get the fields
y = EllipseDecorator.prototype.createPointerFields.apply(this, arguments);
while (i < this.fields.length) {
// Update the event handlers
ptr = this.fields[i].name;
// TODO: This should be changed in EasyDAG
this.fields[i].selectTarget = this.getValidNestedLayers.bind(this, ptr);
i++;
}
return y;
};
LayerDecorator.prototype.getValidNestedLayers = function(ptr) {
var tgtId = this._node.pointers[ptr];
if (tgtId) {
WebGMEGlobal.State.registerActiveObject(tgtId);
} else {
this.createLayerArg(ptr);
}
};
LayerDecorator.prototype.createLayerArg = function(ptr) {
// Find the Architecture node type
var metanodes = this.client.getAllMetaNodes(),
base = metanodes.find(node => node.getAttribute('name') === 'Architecture'),
baseId,
msg = `Creating layers for "${ptr}" of ${this._node.name}`,
tgtId;
if (!base) {
return this.logger.error('Could not find "Architecture" type!');
}
// Create a nested "architecture" node and set the ptr target to it
baseId = base.getId();
this.client.startTransaction(msg);
tgtId = this.client.createChild({
parentId: this._node.id,
baseId: baseId
});
this.client.setAttributes(tgtId, 'name', `${ptr} (${this._node.name})`);
this.savePointer(ptr, tgtId);
this.client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(tgtId);
};
LayerDecorator.prototype.savePointer = function(ptr, to) {
if (!to) { // delete the current target
var currentId = this._node.pointers[ptr],
name = this._node.name;
// If the target is contained in the current node, delete it!
if (currentId.indexOf(this._node.id) === 0) {
this.client.startTransaction(`Removing layer for ${ptr} of ${name}`);
this.client.delMoreNodes([currentId]);
this.client.completeTransaction();
this.logger.info(`Removed ${ptr} and deleted target (${currentId})`);
} else {
this.logger.info(`Removed ${ptr} (external architecture)`);
}
} else { // create and set the node
EllipseDecorator.prototype.savePointer.apply(this, arguments);
}
};
return LayerDecorator;
});
@@ -0,0 +1,29 @@
/* globals define, _ */
define([
'decorators/EllipseDecorator/EasyDAG/PointerField'
], function(
PointerField
) {
// The LayerField behaves the same as PointerFields but it shows "click to view"
// if it has a value
var LayerField = function() {
PointerField.apply(this, arguments);
};
_.extend(LayerField.prototype, PointerField.prototype);
LayerField.prototype.getContent = function(content) {
return content && 'click to view';
};
LayerField.prototype.createContent = function(w, y, content) {
PointerField.prototype.createContent.call(this, w, y, this.getContent(content));
this.$content.attr('font-style', 'italic');
};
LayerField.prototype.setValue = function(content) {
PointerField.prototype.setValue.call(this, this.getContent(content));
};
return LayerField;
});
@@ -0,0 +1,39 @@
/*globals define, _*/
/*jshint browser: true, camelcase: false*/
define([
'js/Decorators/DecoratorBase',
'./EasyDAG/LayerDecorator.EasyDAGWidget'
], function (
DecoratorBase,
LayerDecoratorEasyDAGWidget
) {
'use strict';
var LayerDecorator,
__parent__ = DecoratorBase,
__parent_proto__ = DecoratorBase.prototype,
DECORATOR_ID = 'LayerDecorator';
LayerDecorator = function (params) {
var opts = _.extend({loggerName: this.DECORATORID}, params);
__parent__.apply(this, [opts]);
this.logger.debug('LayerDecorator ctor');
};
_.extend(LayerDecorator.prototype, __parent_proto__);
LayerDecorator.prototype.DECORATORID = DECORATOR_ID;
/*********************** OVERRIDE DecoratorBase MEMBERS **************************/
LayerDecorator.prototype.initializeSupportedWidgetMap = function () {
this.supportedWidgetMap = {
EasyDAG: LayerDecoratorEasyDAGWidget
};
};
return LayerDecorator;
});
@@ -1,4 +1,4 @@
/*globals define, $,_*/
/*globals define, _*/
/*jshint browser: true, camelcase: false*/
/**
+38 -12
Ver Arquivo
@@ -79,7 +79,11 @@ define([
};
CreateExecution.prototype.createExecution = function (node) {
var name = this.core.getAttribute(node, 'name');
// Get the user supplied name
var name = this.core.getAttribute(node, 'name'),
config = this.getCurrentConfig(),
basename = config.name || (name + '_execution');
// Given a pipeline, copy all the operations to a custom job
// - Copy the operations
@@ -89,38 +93,46 @@ define([
// - 'console' show console output (future feature)
// - Update the references
var tgtNode,
execName,
copies,
opTuples, // [[op, index], [op, index], ...]
dataMapping = {};
return this.getExecutionDir()
.then(execDir => {
var execDirId = this.core.getPath(execDir),
execTypeId = this.core.getPath(this.META.Execution);
this.logger.debug(`Creating execution node in ${execDirId} (type is ${execTypeId})`);
tgtNode = this.core.createNode({
base: this.META.Execution,
parent: execDir
});
// Get a unique name
return this.getUniqueExecName(name + '_execution');
this.logger.debug(`About to get a unique name starting w/ ${basename}`);
return this.getUniqueExecName(basename);
})
.then(execName => {
var isSnapshot = this.getCurrentConfig().snapshot;
.then(_execName => {
var isSnapshot = !this.getCurrentConfig().debug,
originName = this.core.getAttribute(this.activeNode, 'name'),
oId = this.core.getPath(this.activeNode),
tgtId = this.core.getPath(tgtNode);
this.logger.debug(`Creating execution ${execName}`);
execName = _execName;
this.logger.debug(`Configuring execution attributes (${execName})`);
// Set all the metadata for the new execution
this.core.setAttribute(tgtNode, 'name', execName);
this.core.setAttribute(tgtNode, 'snapshot', isSnapshot);
this.core.setAttribute(tgtNode, 'tagname', execName);
this.core.setAttribute(tgtNode, 'createdAt', Date.now());
this.logger.debug(`Setting origin pipeline to ${originName} (${oId})`);
this.core.setPointer(tgtNode, 'origin', this.activeNode);
this.logger.debug(`Adding ${tgtId} to execution list of ${originName} (${oId})`);
this.core.addMember(this.activeNode, 'executions', tgtNode);
return this.project.createTag(
execName.replace(/[ -]/g, '_'),
this.currentHash
);
this.logger.debug(`Creating tag "${execName}"`);
})
.then(() => this.core.loadChildren(node))
.then(children => {
@@ -128,6 +140,7 @@ define([
this.logger.warn('No children in pipeline. Will proceed anyway');
}
this.logger.debug(`Copying operations to "${execName}"`);
return this.copyOperations(children, tgtNode);
})
.then(copiedPairs => {
@@ -138,6 +151,7 @@ define([
.filter(pair => this.core.isTypeOf(pair[0], this.META.Operation));
// Create a mapping of old names to new names
this.logger.debug('Creating mapping of old->new');
return Q.all(opTuples.map(pair =>
// Add the input/output mappings to the dataMapping
this.addDataToMap(originals[pair[1]], pair[0], dataMapping)
@@ -145,22 +159,30 @@ define([
);
})
.then(() => { // datamapping is set!
this.logger.debug('Updating references...');
this.updateReferences(copies, dataMapping);
this.logger.debug('Placing operations in Job containers');
this.boxOperations(opTuples.map(o => o[0]), tgtNode);
this.logger.debug('Finished! Saving...');
return this.save(`Created execution from ${name}`);
})
.then(() => this.project.createTag(execName, this.currentHash))
.then(() => tgtNode); // return tgtNode
};
CreateExecution.prototype.getUniqueExecName = function (basename) {
var name = basename,
taken = {},
var taken = {},
name,
i = 2;
basename = basename.replace(/[^\da-zA-Z_]/g, '_');
name = basename;
// Get a unique name wrt the tags and the other executions
return this.project.getTags()
.then(tags => {
Object.keys(tags).forEach(name => taken[name] = true);
this.logger.debug(`Existing tags are ${Object.keys(tags).join(',')}`);
// Get the other executions
return this.getExecutionDir();
@@ -171,19 +193,22 @@ define([
})
.then(execs => {
var names = execs.map(exec => this.core.getAttribute(exec, 'name'));
this.logger.debug(`Existing names are ${names.join(',')}`);
names.forEach(name => taken[name] = true);
while (taken[name]) {
name = basename + '_' + (i++);
}
this.logger.debug(`Unique name is "${name}"`);
return name;
});
};
CreateExecution.prototype.copyOperations = function (nodes, dst) {
var snapshot = this.getCurrentConfig().snapshot;
var snapshot = !this.getCurrentConfig().debug;
if (snapshot) {
this.logger.debug('Execution is a snapshot -> severing the inheritance');
return Q.all(nodes.map(node => {
if (this.isLocalOperation(node) ||
this.isMetaTypeOf(node, this.META.Transporter)) {
@@ -198,6 +223,7 @@ define([
);
} else if (nodes.length) {
this.logger.debug('Execution is not a snapshot -> doing a simple copy');
var copies = this.core.copyNodes(nodes, dst);
return nodes.map((node, i) => [node, copies[i]]);
}
+182 -157
Ver Arquivo
@@ -1,31 +1,25 @@
/*globals define*/
/*jshint node:true, browser:true*/
/**
* Generated by PluginGenerator 0.14.0 from webgme on Tue Mar 15 2016 21:19:45 GMT-0500 (CDT).
*/
define([
'plugin/PluginConfig',
'plugin/PluginBase',
'deepforge/js-yaml.min',
'common/util/guid',
'deepforge/Constants',
'deepforge/utils',
'js/RegistryKeys',
'js/Constants',
'js/Panels/MetaEditor/MetaEditorConstants',
'underscore',
'text!deepforge/layers.json',
'./schemas/index',
'text!./metadata.json'
], function (
PluginConfig,
PluginBase,
yaml,
generateGuid,
Constants,
utils,
REGISTRY_KEYS,
CONSTANTS,
META_CONSTANTS,
_,
DEFAULT_LAYERS,
Schemas,
metadata
) {
'use strict';
@@ -61,110 +55,102 @@ define([
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
CreateTorchMeta.prototype.main = function (callback) {
// Use self to access core, project, result, logger etc from PluginBase.
// These are all instantiated at this point.
var self = this;
if (!this.META.Language) {
callback('"Language" container required to run plugin', this.result);
return callback('"Language" container required to run plugin', this.result);
}
// Extra layer names
this.getJsonLayers((err, text) => {
if (err) {
return callback(err, this.result);
// The format is...
// - (Abstract) CategoryLayerTypes
// - LayerName
// - Attributes (if exists)
var layers,
content = {},
categories,
config = this.getCurrentConfig(),
nodes = {};
try {
layers = this.getJsonLayers();
} catch (e) {
return callback('JSON parse error: ' + e, this.result);
}
layers.forEach(layer => {
if (!content[layer.type]) {
content[layer.type] = [];
}
// The format is...
// - (Abstract) CategoryLayerTypes
// - LayerName
// - Attributes (if exists)
var content = {},
categories,
config = this.getCurrentConfig(),
nodes = {},
layers;
try {
layers = JSON.parse(text);
} catch (e) {
return callback('JSON parse error: ' + e, this.result);
}
layers.forEach(layer => {
if (!content[layer.type]) {
content[layer.type] = [];
}
content[layer.type].push(layer);
});
categories = Object.keys(content);
// Create the base class, if needed
if (!this.META.Layer) {
this.META.Layer = this.createMetaNode('Layer', this.META.FCO);
}
// Create the category nodes
categories
.forEach(name => {
// Create a tab for each
this.metaSheets[name] = this.createMetaSheetTab(name);
this.sheetCounts[name] = 0;
nodes[name] = this.createMetaNode(name, this.META.Layer, name);
});
// Make them abstract
categories
.forEach(name => this.core.setRegistry(nodes[name], 'isAbstract', true));
if (config.removeOldLayers) {
var isNewLayer = {},
newLayers = layers.map(layer => layer.name),
oldLayers,
oldNames;
newLayers = newLayers.concat(categories); // add the category nodes
newLayers.forEach(name => isNewLayer[name] = true);
// Set the newLayer nodes 'base' to 'Layer' so we don't accidentally
// delete them
newLayers
.map(name => this.META[name])
.filter(layer => !!layer)
.forEach(layer => this.core.setPointer(layer, 'base', this.META.Layer));
oldLayers = Object.keys(this.META)
.filter(name => name !== 'Layer')
.map(name => this.META[name])
.filter(node => this.isMetaTypeOf(node, this.META.Layer))
.filter(node => !isNewLayer[this.core.getAttribute(node, 'name')]);
oldNames = oldLayers.map(l => this.core.getAttribute(l, 'name'));
// Get the old layer names
this.logger.debug(`Removing layers: ${oldNames.join(', ')}`);
oldLayers.forEach(layer => this.core.deleteNode(layer));
}
// Create the actual nodes
categories.forEach(cat => {
content[cat]
.forEach(layer => {
var attrs = layer.params,
name = layer.name;
nodes[name] = this.createMetaNode(name, nodes[cat], cat, attrs);
// Make the node non-abstract
this.core.setRegistry(nodes[name], 'isAbstract', false);
});
});
self.save('CreateTorchMeta updated model.', function (err) {
if (err) {
callback(err, self.result);
return;
}
self.result.setSuccess(true);
callback(null, self.result);
});
content[layer.type].push(layer);
});
categories = Object.keys(content);
// Create the base class, if needed
if (!this.META.Layer) {
this.META.Layer = this.createMetaNode('Layer', this.META.FCO);
}
// Create the category nodes
categories
.forEach(name => {
// Create a tab for each
this.metaSheets[name] = this.createMetaSheetTab(name);
this.sheetCounts[name] = 0;
nodes[name] = this.createMetaNode(name, this.META.Layer, name);
});
// Make them abstract
categories
.forEach(name => this.core.setRegistry(nodes[name], 'isAbstract', true));
if (config.removeOldLayers) {
var isNewLayer = {},
newLayers = layers.map(layer => layer.name),
oldLayers,
oldNames;
newLayers = newLayers.concat(categories); // add the category nodes
newLayers.forEach(name => isNewLayer[name] = true);
// Set the newLayer nodes 'base' to 'Layer' so we don't accidentally
// delete them
newLayers
.map(name => this.META[name])
.filter(layer => !!layer)
.forEach(layer => this.core.setBase(layer, this.META.Layer));
oldLayers = Object.keys(this.META)
.filter(name => name !== 'Layer')
.map(name => this.META[name])
.filter(node => this.isMetaTypeOf(node, this.META.Layer))
.filter(node => !isNewLayer[this.core.getAttribute(node, 'name')]);
oldNames = oldLayers.map(l => this.core.getAttribute(l, 'name'));
// Get the old layer names
this.logger.debug(`Removing layers: ${oldNames.join(', ')}`);
oldLayers.forEach(layer => this.core.deleteNode(layer));
}
// Create the actual nodes
categories.forEach(cat => {
content[cat]
.forEach(layer => {
var name = layer.name,
node;
node = this.createMetaNode(name, nodes[cat], cat, layer);
// Make the node non-abstract
if (node) {
this.core.setRegistry(node, 'isAbstract', false);
nodes[name] = node;
}
});
});
this.save('CreateTorchMeta updated model.')
.then(() => {
this.result.setSuccess(true);
callback(null, this.result);
})
.fail(err => callback(err, this.result));
};
CreateTorchMeta.prototype.removeFromMeta = function (nodeId) {
@@ -206,28 +192,45 @@ define([
return sheet.SetID;
};
CreateTorchMeta.prototype.getJsonLayers = function (callback) {
var config = this.getCurrentConfig();
CreateTorchMeta.prototype.getJsonLayers = function () {
var config = this.getCurrentConfig(),
schema = config.layerSchema;
if (config.layerNameHash) {
this.blobClient.getObject(config.layerNameHash, (err, buffer) => {
if (err) {
return callback(err, this.result);
}
var text = String.fromCharCode.apply(null, new Uint8Array(buffer));
return callback(null, text);
});
} else {
return callback(null, DEFAULT_LAYERS);
if (schema === 'all') {
return Object.keys(Schemas).map(key => JSON.parse(Schemas[key]))
.reduce((l1, l2) => l1.concat(l2), []);
}
return JSON.parse(Schemas[schema]);
};
CreateTorchMeta.prototype.createMetaNode = function (name, base, tabName, attrs) {
// Some helper methods w/ attribute handling
var LUA_TO_GME = {
boolean: 'boolean',
number: 'float',
string: 'string'
};
var isLayerAttribute = type => type && type.substring(0, 3) === 'nn.';
CreateTorchMeta.prototype.createMetaNode = function (name, base, tabName, layer) {
var node = this.META[name],
nodeId = node && this.core.getPath(node),
tabId = this.metaSheets[tabName],
position = this.getPositionFor(name, tabName);
position = this.getPositionFor(name, tabName),
setters = {},
defaults = {},
types = {},
type,
attrs,
desc;
if (layer) {
attrs = layer.params;
setters = layer.setters;
defaults = layer.defaults;
types = layer.types || types;
}
if (!tabId) {
this.logger.error(`No meta sheet for ${tabName}`);
}
@@ -244,7 +247,7 @@ define([
} else {
// Remove from meta
this.removeFromMeta(nodeId);
this.core.setPointer(node, 'base', base);
this.core.setBase(node, base);
}
// Add it to the meta sheet
@@ -269,14 +272,16 @@ define([
if (attrs) { // Add the attributes
// Remove attributes not in the given list
var currentAttrs = this.core.getValidAttributeNames(node),
rmAttrs;
defVal,
rmAttrs,
simpleAttrs,
rmPtrs;
rmAttrs = _.difference(currentAttrs, attrs) // old attribute names
.filter(attr => attr !== 'name');
simpleAttrs = attrs.filter(name => !isLayerAttribute(types[name]));
rmAttrs = _.difference(currentAttrs, simpleAttrs) // old attribute names
.filter(attr => attr !== 'name')
.filter(attr => !setters[attr]);
if (rmAttrs.length) {
this.logger.debug(`Removing ${rmAttrs.join(', ')} from ${name}`);
}
rmAttrs.forEach(attr => {
this.core.delAttributeMeta(node, attr);
if (this.core.getOwnAttribute(node, attr) !== undefined) {
@@ -284,11 +289,38 @@ define([
}
});
attrs.forEach((name, index) => {
var desc = {};
desc.argindex = index;
desc.default = '';
this.addAttribute(name, node, desc);
// Remove all old pointers
rmPtrs = _.difference(this.core.getPointerNames(node), currentAttrs)
.filter(ptr => ptr !== 'base');
if (rmPtrs.length + rmAttrs.length) {
this.logger.debug(`Removing ${rmPtrs.concat(rmAttrs).join(', ')} from ${name}`);
}
rmPtrs.forEach(ptr => this.core.delPointerMeta(node, ptr));
attrs.forEach(name => {
desc = {};
defVal = defaults.hasOwnProperty(name) ? defaults[name] : '';
type = LUA_TO_GME[types[name]];
if (type) {
desc.type = type;
}
if (isLayerAttribute(types[name])) { // Check if it is an nn layer type
// If so, create a pointer rather than attribute
this.addLayerAttribute(name, node);
this.logger.debug(`${name} is a layer type attribute`);
} else {
this.addAttribute(name, node, desc, defVal);
}
});
this.core.setAttribute(node, Constants.CTOR_ARGS_ATTR, attrs.join(','));
// Add the setters to the meta
Object.keys(setters).forEach(name => {
desc = utils.getSetterSchema(name, setters, defaults);
defVal = desc.default;
delete desc.default;
this.addAttribute(name, node, desc, defVal);
});
}
this.logger.debug(`added ${name} to the meta`);
@@ -323,41 +355,34 @@ define([
};
};
CreateTorchMeta.prototype.addAttribute = function (name, node, def) {
var initial,
schema = {};
CreateTorchMeta.prototype.addLayerAttribute = function (name, node) {
// No default value support for now...
// Create a pointer of the given type on the node
this.core.setPointerMetaTarget(node, name, this.META.Architecture, 1, 1);
this.core.setPointerMetaLimits(node, name, 1, 1);
};
schema.type = def.type || 'string';
CreateTorchMeta.prototype.addAttribute = function (name, node, schema, defVal) {
schema.type = schema.type || 'string';
if (schema.type === 'list') { // FIXME: add support for lists
schema.type = 'string';
}
if (def.min !== undefined) {
schema.min = +def.min;
if (schema.min !== undefined) {
schema.min = +schema.min;
}
if (def.max !== undefined) {
if (schema.max !== undefined) {
// Set the min, max
schema.max = +def.max;
schema.max = +schema.max;
}
// Add the infer flag
if (def.infer) {
schema.infer = def.infer;
}
// Add the argindex flag
schema.argindex = def.argindex;
// Create the attribute and set the schema
this.core.setAttributeMeta(node, name, schema);
// Determine a default value
initial = def.hasOwnProperty('default') ? def.default : def.min || null;
if (schema.type === 'boolean') {
initial = initial !== null ? initial : false;
if (defVal) {
this.core.setAttribute(node, name, defVal);
}
this.core.setAttribute(node, name, initial);
};
return CreateTorchMeta;
+23 -18
Ver Arquivo
@@ -7,24 +7,29 @@
"src": "",
"class": "glyphicon glyphicon-ok-circle"
},
"disableServerSideExecution": false,
"disableServerSideExecution": true,
"disableBrowserSideExecution": false,
"configStructure": [
{
"name": "layerNameHash",
"displayName": "Torch Layers",
"description": "Yaml file of torch layer descriptors (optional)",
"value": "",
"valueType": "asset",
"readOnly": false
},
{
"name": "removeOldLayers",
"displayName": "Delete old layers",
"description": "Delete all layers not in the current description",
"value": true,
"valueType": "boolean",
"readOnly": false
}
{
"name": "layerSchema",
"displayName": "Torch Libraries",
"description": "Torch nn libraries to create layers from",
"value": "all",
"valueItems": [
"nn",
"rnn",
"all"
],
"valueType": "string",
"readOnly": false
},
{
"name": "removeOldLayers",
"displayName": "Delete old layers",
"description": "Delete all layers not in the current description",
"value": true,
"valueType": "boolean",
"readOnly": false
}
]
}
}
+13
Ver Arquivo
@@ -0,0 +1,13 @@
/*globals define*/
define([
'text!./nn.json',
'text!./rnn.json'
], function(
nn,
rnn
) {
return {
nn: nn,
rnn: rnn
};
});
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+178
Ver Arquivo
@@ -0,0 +1,178 @@
[
{
"name": "CopyGrad",
"baseType": "Identity",
"setters": {},
"defaults": {},
"type": "RNN"
},
{
"name": "FastLSTM",
"baseType": "LSTM",
"params": [
"inputSize",
"outputSize",
"rho",
"eps",
"momentum",
"affine"
],
"setters": {},
"types": {
"eps": "number",
"momentum": "number"
},
"defaults": {
"momentum": 0.1,
"eps": 0.1
},
"type": "RNN"
},
{
"name": "LSTM",
"baseType": "AbstractRecurrent",
"params": [
"inputSize",
"outputSize",
"rho",
"cell2gate"
],
"setters": {},
"types": {
"rho": "number"
},
"defaults": {
"rho": 9999
},
"type": "RNN"
},
{
"name": "LinearNoBias",
"baseType": "Linear",
"params": [
"inputSize",
"outputSize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "Simple"
},
{
"name": "LookupTableMaskZero",
"baseType": "LookupTable",
"params": [
"nIndex",
"nOutput"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "NormStabilizer",
"baseType": "AbstractRecurrent",
"params": [
"beta"
],
"setters": {},
"defaults": {},
"type": "RNN"
},
{
"name": "Recurrent",
"baseType": "AbstractRecurrent",
"params": [
"start",
"input",
"feedback",
"transfer",
"rho",
"merge"
],
"setters": {},
"types": {
"start": "nn.Module",
"transfer": "nn.Module",
"feedback": "nn.Module",
"input": "nn.Module"
},
"defaults": {},
"type": "RNN"
},
{
"name": "SAdd",
"baseType": "Module",
"params": [
"addend",
"negate"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqBRNN",
"baseType": "Container",
"params": [
"inputDim",
"hiddenDim",
"batchFirst"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqGRU",
"baseType": "Module",
"params": [
"inputSize",
"outputSize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqLSTM",
"baseType": "Module",
"params": [
"inputsize",
"hiddensize",
"outputsize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqLSTMP",
"baseType": "SeqLSTM",
"params": [
"inputsize",
"hiddensize",
"outputsize"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
},
{
"name": "SeqReverseSequence",
"baseType": "Module",
"params": [
"dim"
],
"setters": {},
"types": {},
"defaults": {},
"type": "RNN"
}
]
@@ -0,0 +1,37 @@
/* eslint-disable no-console */
// Update the metadata and schemas/index based on the new schemas in schemas/
// Update metadata
var fs = require('fs'),
path = require('path'),
schemas,
metadata = require('./metadata.json'),
schemaList;
schemas = fs.readdirSync(__dirname + '/schemas/')
.filter(name => path.extname(name) === '.json')
.map(name => name.replace(/\.json$/, ''));
console.log('Discovered schemas: ' + schemas.join(', '));
schemaList = metadata.configStructure.find(struct => struct.name === 'layerSchema');
schemaList.valueItems = schemas.concat('all');
console.log('Updating metadata...');
fs.writeFileSync(__dirname + '/metadata.json', JSON.stringify(metadata, null, 2));
// Update index.js
var index =
`/*globals define*/
define([
${schemas.map(s => `'text!./${s}.json'`).join(',\n ')}
], function(
${schemas.map(s => s).join(',\n ')}
) {
return {
${schemas.map(s => s + ': ' + s).join(',\n ')}
};
});`;
console.log('Updating index.js...');
fs.writeFileSync(__dirname + '/schemas/index.js', index);
+289 -64
Ver Arquivo
@@ -2,6 +2,7 @@
/*jshint node:true, browser:true*/
define([
'common/storage/constants',
'text!./metadata.json',
'executor/ExecutorClient',
'plugin/PluginBase',
@@ -12,6 +13,7 @@ define([
'q',
'underscore'
], function (
STORAGE_CONSTANTS,
pluginMetadata,
ExecutorClient,
PluginBase,
@@ -46,6 +48,7 @@ define([
this._markForDeletion = {}; // id -> node
this._oldMetadataByName = {}; // name -> id
this.lastAppliedCmd = {};
this.canceled = false;
};
/**
@@ -79,10 +82,43 @@ define([
}
this._callback = callback;
this.currentForkName = null;
this.prepare()
.then(() => this.executeJob(this.activeNode));
};
ExecuteJob.prototype.updateForkName = function (basename) {
basename = basename + '_fork';
basename = basename.replace(/[- ]/g, '_');
return this.project.getBranches().then(branches => {
var names = Object.keys(branches),
name = basename,
i = 2;
while (names.indexOf(name) !== -1) {
name = basename + '_' + i;
i++;
}
this.forkName = name;
});
};
// Override 'save' to notify the user on fork
ExecuteJob.prototype.save = function (msg) {
var name = this.core.getAttribute(this.activeNode, 'name');
return this.updateForkName(name)
.then(() => PluginBase.prototype.save.call(this, msg))
.then(result => {
var msg;
if (result.status === STORAGE_CONSTANTS.FORKED) {
msg = `"${name}" execution has forked to "${result.forkName}"`;
this.currentForkName = result.forkName;
this.sendNotification(msg);
}
});
};
ExecuteJob.prototype.getConnections = function (nodes) {
var conns = [];
for (var i = nodes.length; i--;) {
@@ -129,6 +165,8 @@ define([
name,
id,
idsToDelete = [],
type,
base,
child;
this.lastAppliedCmd[nodeId] = 0;
@@ -142,9 +180,16 @@ define([
if (this.isMetaTypeOf(child, this.META.Metadata)) {
id = this.core.getPath(child);
name = this.core.getAttribute(child, 'name');
base = this.core.getBase(child);
type = this.core.getAttribute(base, 'name');
this._markForDeletion[nodeId][id] = child;
this._oldMetadataByName[nodeId][name] = id;
// namespace by metadata type
if (!this._oldMetadataByName[nodeId][type]) {
this._oldMetadataByName[nodeId][type] = {};
}
this._oldMetadataByName[nodeId][type][name] = id;
// children of metadata nodes get deleted
idsToDelete = idsToDelete
@@ -168,6 +213,24 @@ define([
}
delete this.lastAppliedCmd[nodeId];
delete this._markForDeletion[nodeId];
this.core.delAttribute(job, 'jobId');
this.core.delAttribute(job, 'secret');
};
ExecuteJob.prototype.resultMsg = function(msg) {
this.sendNotification(msg);
this.createMessage(null, msg);
};
ExecuteJob.prototype.onOperationCanceled = function(op) {
var job = this.core.getParent(op),
name = this.core.getAttribute(op, 'name'),
msg = `"${name}" canceled!`;
this.core.setAttribute(job, 'status', 'canceled');
this.resultMsg(msg);
this.onComplete(op, null);
};
ExecuteJob.prototype.onOperationFail =
@@ -177,8 +240,8 @@ define([
exec = this.core.getParent(job),
name = this.core.getAttribute(job, 'name'),
jobId = this.core.getPath(job),
status = err ? 'fail' : 'success',
msg = err ? `${name} execution failed: ${err}` :
status = err ? 'fail' : (this.canceled ? 'canceled' : 'success'),
msg = err ? `${name} execution failed!` :
`${name} executed successfully!`,
promise = Q();
@@ -186,8 +249,16 @@ define([
this.logger.info(`Setting ${name} (${jobId}) status to ${status}`);
this.clearOldMetadata(job);
if (this.currentForkName) {
// notify client that the job has completed
this.sendNotification(`"${name}" execution completed on branch "${this.currentForkName}"`);
}
if (err) {
this.logger.warn(`${name} failed: ${err}`);
this.core.setAttribute(exec, 'status', 'failed');
} else if (this.canceled) {
// Should I set this to 'canceled'?
this.core.setAttribute(exec, 'status', 'canceled');
} else {
// Check if all the other jobs are successful. If so, set the
// execution status to 'success'
@@ -213,6 +284,7 @@ define([
});
}
this.createMessage(null, msg);
promise
.then(() => this.save(msg))
.then(() => {
@@ -230,6 +302,24 @@ define([
children.find(child => this.isMetaTypeOf(child, this.META.Operation)));
};
ExecuteJob.prototype.onBlobRetrievalFail = function (node, input, err) {
var job = this.core.getParent(node),
e = `Failed to retrieve "${input}" (${err})`,
consoleErr = `Failed to execute operation: ${e}`;
consoleErr += [
'\n\nA couple things to check out:\n',
'- Has the location of DeepForge\'s blob changed?',
' (Configurable using "blob.dir" in the deepforge config' +
' or setting the DEEPFORGE_BLOB_DIR environment variable)\n',
'- Was this project created using a different blob location?'
].join('\n ');
this.core.setAttribute(job, 'stdout', consoleErr);
this.onOperationFail(node, `Blob retrieval failed for "${name}": ${e}`);
};
ExecuteJob.prototype.executeJob = function (job) {
return this.getOperation(job).then(node => {
var jobId = this.core.getPath(job),
@@ -263,37 +353,46 @@ define([
var hash = files.inputAssets[input];
// data asset for "input"
return this.blobClient.getMetadata(hash);
return this.blobClient.getMetadata(hash)
.fail(err => this.onBlobRetrievalFail(job, input, err));
})
);
})
.then(mds => {
// get (input, filename) tuples
// Record the large files
var inputData = {};
mds.forEach((metadata, i) => {
// add the hashes for each input
var input = inputs[i],
name = metadata.name,
hash = files.inputAssets[input];
data['inputs/' + input + '/' + name] = hash;
inputData['inputs/' + input + '/data'] = {
req: hash,
cache: metadata.content
};
});
delete files.inputAssets;
files['input-data.json'] = JSON.stringify(inputData, null, 2);
// Add pointer assets
Object.keys(files.ptrAssets)
.forEach(path => data[path] = files.ptrAssets[path]);
delete files.ptrAssets;
// Add the executor config
return this.getOutputs(node);
})
.then(outputArgs => {
var config,
outputs,
fileList,
ptrFiles = Object.keys(files.ptrAssets),
file;
files['start.js'] = _.template(Templates.START)(CONSTANTS);
delete files.ptrAssets;
fileList = Object.keys(files).concat(ptrFiles);
outputs = outputArgs.map(pair => pair[0])
.map(name => {
return {
@@ -309,18 +408,17 @@ define([
},
{
name: name + '-all-files',
resultPatterns: []
resultPatterns: fileList
}
);
config = {
cmd: 'bash',
args: ['run.sh'],
cmd: 'node',
args: ['start.js'],
outputInterval: OUTPUT_INTERVAL,
resultArtifacts: outputs
};
files['executor_config.json'] = JSON.stringify(config, null, 4);
files['run.sh'] = Templates.BASH;
// Save the artifact
// Remove empty hashes
@@ -373,7 +471,13 @@ define([
this.logger.debug(`Making a commit from ${this.currentHash}`);
this.save(`Queued "${name}" operation in ${this.pipelineName}`)
.then(() => executor.createJob({hash}))
.then(() => this.watchOperation(executor, hash, opNode, job))
.then(info => {
this.core.setAttribute(job, 'jobId', info.hash);
if (info.secret) { // o.w. it is a cached job!
this.core.setAttribute(job, 'secret', info.secret);
}
return this.watchOperation(executor, hash, opNode, job);
})
.catch(err => this.logger.error(`Could not execute "${name}": ${err}`));
};
@@ -427,6 +531,7 @@ define([
isClass,
metanodes,
classNodes,
inheritanceLvl = {},
code;
this.logger.info('Creating custom layer file...');
@@ -435,13 +540,31 @@ define([
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base);
baseId = this.core.getPath(base),
count = 1;
return isClass[baseId];
// Count the sets back to a class node
while (base) {
if (isClass[baseId]) {
inheritanceLvl[this.core.getPath(node)] = count;
return true;
}
base = this.core.getBase(base);
baseId = this.core.getPath(base);
count++;
}
return false;
});
// Get the code definitions for each
code = classNodes.map(node =>
// Sort by levels of inheritance...
code = classNodes.sort((a, b) => {
var aId = this.core.getPath(a),
bId = this.core.getPath(b);
return inheritanceLvl[aId] > inheritanceLvl[bId];
}).map(node =>
`require './${this.core.getAttribute(node, 'name')}.lua'`
).join('\n');
@@ -542,12 +665,18 @@ define([
})
.then(_tplContents => {
tplContents = _tplContents;
var hashes = inputs
// storing the hash for now...
.map(pair =>
files.inputAssets[pair[0]] = this.core.getAttribute(pair[2], 'data')
);
return Q.all(hashes.map(h => this.blobClient.getMetadata(h)));
var hashes = inputs.map(pair => {
var hash = this.core.getAttribute(pair[2], 'data');
files.inputAssets[pair[0]] = hash;
return {
hash: hash,
name: pair[0]
};
});
return Q.all(hashes.map(pair =>
this.blobClient.getMetadata(pair.hash)
.fail(err => this.onBlobRetrievalFail(node, pair.name, err))));
})
.then(metadatas => {
// Create the deserializer
@@ -666,7 +795,7 @@ define([
return cb(null, files);
})
.fail(e => {
this.logger.error(`Could not generate pointer files for ${this.core.getAttribute(node, 'name')}: ${JSON.stringify(e)}`);
this.logger.error(`Could not generate pointer files for ${this.core.getAttribute(node, 'name')}: ${e.toString()}`);
return cb(e);
});
};
@@ -675,7 +804,19 @@ define([
var jobId = this.core.getPath(job),
opId = this.core.getPath(op),
info,
name;
secret,
name = this.core.getAttribute(job, 'name');
// If canceled, stop the operation
if (this.canceled) {
secret = this.core.getAttribute(job, 'secret');
if (secret) {
executor.cancelJob(hash, secret);
this.core.delAttribute(job, 'secret');
this.canceled = true;
return this.onOperationCanceled(op);
}
}
return executor.getInfo(hash)
.then(_info => { // Update the job's stdout
@@ -690,15 +831,21 @@ define([
.then(outputLines => {
var stdout = this.core.getAttribute(job, 'stdout'),
output = outputLines.map(o => o.output).join(''),
jobName = this.core.getAttribute(job, 'name');
last = stdout.lastIndexOf('\n'),
lastLine;
// parse deepforge commands
output = this.parseForMetadataCmds(job, output);
if (last !== -1) {
stdout = stdout.substring(0, last+1);
lastLine = stdout.substring(last+1);
output = lastLine + output;
}
output = this.processStdout(job, output, true);
if (output) {
stdout += output;
this.core.setAttribute(job, 'stdout', stdout);
return this.save(`Received stdout for ${jobName}`);
return this.save(`Received stdout for ${name}`);
}
});
}
@@ -708,7 +855,6 @@ define([
if (info.status === 'RUNNING' &&
this.core.getAttribute(job, 'status') !== 'running') {
name = this.core.getAttribute(job, 'name');
this.core.setAttribute(job, 'status', 'running');
this.save(`Started "${name}" operation in ${this.pipelineName}`);
}
@@ -720,26 +866,40 @@ define([
return;
}
name = this.core.getAttribute(job, 'name');
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
return this.blobClient.getArtifact(info.resultHashes.stdout)
.then(artifact => {
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
return this.blobClient.getObjectAsString(stdoutHash);
})
.then(stdout => {
// Parse the remaining code
stdout = this.parseForMetadataCmds(job, stdout, true);
this.core.setAttribute(job, 'stdout', stdout);
if (info.status !== 'SUCCESS') {
// Download all files
this.result.addArtifact(info.resultHashes[name + '-all-files']);
// Set the job to failed! Store the error
this.onOperationFail(op, `Operation "${opId}" failed! ${JSON.stringify(info)}`);
} else {
this.onDistOperationComplete(op, info);
}
});
if (info.status === 'CANCELED') {
// If it was cancelled, the pipeline has been stopped
this.logger.debug(`"${name}" has been CANCELED!`);
this.canceled = true;
return this.onOperationCanceled(op);
}
if (info.status === 'SUCCESS' || info.status === 'FAILED_TO_EXECUTE') {
this.core.setAttribute(job, 'execFiles', info.resultHashes[name + '-all-files']);
return this.blobClient.getArtifact(info.resultHashes.stdout)
.then(artifact => {
var stdoutHash = artifact.descriptor.content[STDOUT_FILE].content;
return this.blobClient.getObjectAsString(stdoutHash);
})
.then(stdout => {
// Parse the remaining code
stdout = this.processStdout(job, stdout);
this.core.setAttribute(job, 'stdout', stdout);
if (info.status !== 'SUCCESS') {
// Download all files
this.result.addArtifact(info.resultHashes[name + '-all-files']);
// Set the job to failed! Store the error
this.onOperationFail(op, `Operation "${opId}" failed! ${JSON.stringify(info)}`);
} else {
this.onDistOperationComplete(op, info);
}
});
} else { // something bad happened...
var err = `Failed to execute operation "${opId}": ${info.status}`,
consoleErr = `Failed to execute operation: ${info.status}`;
this.core.setAttribute(job, 'stdout', consoleErr);
this.logger.error(err);
this.onOperationFail(op, err);
}
})
.catch(err => this.logger.error(`Could not get op info for ${opId}: ${err}`));
};
@@ -825,18 +985,47 @@ define([
LocalExecutor.prototype
);
ExecuteJob.prototype.processStdout = function (job, text, continued) {
// resolve \r
var lines,
chars,
result,
i = 0;
text = text.replace(/\u0000/g, '');
lines = text.split('\n');
for (var l = lines.length-1; l >= 0; l--) {
i = 0;
chars = lines[l].split('');
result = [];
for (var c = 0; c < chars.length; c++) {
if (chars[c] === '\r') {
i = 0;
}
result[i] = chars[c];
i++;
}
lines[l] = result.join('');
}
// ... and metadata commands
return this.parseForMetadataCmds(job, lines, !continued);
};
//////////////////////////// Metadata ////////////////////////////
ExecuteJob.prototype.parseForMetadataCmds = function (job, text, skip) {
ExecuteJob.prototype.parseForMetadataCmds = function (job, lines, skip) {
var jobId = this.core.getPath(job),
lines = text.split('\n'),
args,
result = [],
cmdCnt = 0,
ansiRegex = /\[\d+(;\d+)?m/g,
cmd;
for (var i = 0; i < lines.length; i++) {
// Check for a deepforge command
if (lines[i].indexOf(CONSTANTS.START_CMD) === 0) {
if (lines[i].indexOf(CONSTANTS.START_CMD) !== -1) {
lines[i] = lines[i].replace(ansiRegex, '');
cmdCnt++;
args = lines[i].split(/\s+/);
args.shift();
@@ -858,23 +1047,14 @@ define([
ExecuteJob.prototype[CONSTANTS.GRAPH_CREATE] = function (job, id) {
var graph,
name = Array.prototype.slice.call(arguments, 2).join(' '),
jobId = this.core.getPath(job),
oldMetadata = this._oldMetadataByName[jobId],
oldId;
jobId = this.core.getPath(job);
id = jobId + '/' + id;
this.logger.info(`Creating graph ${id} named ${name}`);
// Check if the graph already exists
if (oldMetadata && oldMetadata[name]) {
oldId = oldMetadata[name];
graph = this._markForDeletion[jobId][oldId];
// Reset points
this.core.setAttribute(graph, 'points', '');
delete this._markForDeletion[jobId][oldId];
} else { // create new graph
graph = this._getExistingMetadata(jobId, 'Graph', name);
if (!graph) {
graph = this.core.createNode({
base: this.META.Graph,
parent: job
@@ -890,6 +1070,7 @@ define([
ExecuteJob.prototype[CONSTANTS.GRAPH_PLOT] = function (job, id, x, y) {
var jobId = this.core.getPath(job),
nonNum = /[^\d\.]*/g,
graph,
points;
@@ -902,6 +1083,9 @@ define([
return;
}
// Clean the points by removing and special characters
x = x.replace(nonNum, '');
y = y.replace(nonNum, '');
points = this.core.getAttribute(graph, 'points');
points += `${x},${y};`;
this.core.setAttribute(graph, 'points', points);
@@ -923,5 +1107,46 @@ define([
this._metadata[jobId + '/' + id] = line;
};
ExecuteJob.prototype[CONSTANTS.IMAGE] = function (job, hash) {
var jobId = this.core.getPath(job),
name = Array.prototype.slice.call(arguments, 2).join(' '),
id = jobId + '/IMAGE/' + name,
imageNode = this._metadata[id]; // Look for the metadata imageNode
id = jobId + '/' + id;
this.logger.info(`Creating graph ${id} named ${name}`);
if (!imageNode) {
// Check if the imageNode already exists
imageNode = this._getExistingMetadata(jobId, 'Image', name);
if (!imageNode) {
imageNode = this.core.createNode({
base: this.META.Image,
parent: job
});
this.core.setAttribute(imageNode, 'name', name);
}
this._metadata[id] = imageNode;
}
this.core.setAttribute(imageNode, 'data', hash);
};
ExecuteJob.prototype._getExistingMetadata = function (jobId, type, name) {
var oldMetadata = this._oldMetadataByName[jobId] &&
this._oldMetadataByName[jobId][type],
node,
id;
if (oldMetadata && oldMetadata[name]) {
id = oldMetadata[name];
node = this._markForDeletion[jobId][id];
delete this._markForDeletion[jobId][id];
}
return node || null;
};
return ExecuteJob;
});
@@ -19,6 +19,7 @@ function deepforge._cmd(...)
print(cmd)
end
-- Graph support
Graph = torch.class('deepforge.Graph')
function Graph:__init(name)
@@ -36,6 +37,7 @@ function _Line:__init(graphId, name, opts)
end
function _Line:add(x, y)
assert(type(x) == "number" and type(y) == "number", "adding point (" .. tostring(x) .. ", " .. tostring(y) .. ") to " .. self.name .. " failed: expected (number, number)")
deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
end
@@ -43,4 +45,21 @@ function Graph:line(name, opts)
return deepforge._Line(self.id, name, opts)
end
-- Image support
function deepforge.image(name, tensor)
require 'image'
require 'paths'
-- save it in the tmp directory
local filename = name .. '.png'
local path = paths.concat('metadata', filename)
if paths.dir('metadata') == nil then
paths.mkdir('metadata')
end
image.save(path, tensor)
deepforge._cmd("<%= IMAGE %>", name)
end
return deepforge
@@ -1,6 +1,6 @@
require 'paths'
local path = 'inputs/<%= name %>/<%= filename %>'
local abs_path = paths.concat('inputs', '<%= name %>', '<%= filename %>')
local path = 'inputs/<%= name %>/data'
local abs_path = paths.concat('inputs', '<%= name %>', 'data')
<%= code %>
+3 -2
Ver Arquivo
@@ -1,11 +1,13 @@
/*globals define*/
define([
'text!./start.ejs',
'text!./entry.ejs',
'text!./main.ejs',
'text!./deepforge.ejs',
'text!./serialize.ejs',
'text!./deserialize.ejs'
], function(
START,
ENTRY,
MAIN,
DEEPFORGE,
@@ -13,9 +15,8 @@ define([
DESERIALIZE
) {
var BASH = 'th init.lua 2>&1';
return {
BASH,
START,
ENTRY,
MAIN,
SERIALIZE,
+224
Ver Arquivo
@@ -0,0 +1,224 @@
// A wrapper for the torch script which:
// - merges stdout, stderr
// - receives some commands and uploads intermediate data
var spawn = require('child_process').spawn,
fs = require('fs'),
path = require('path'),
log = console.error,
logger = {};
// Create the stderr only logger
['error', 'warn', 'info', 'log', 'debug'].forEach(method => logger[method] = log);
// Get the BlobClient...
var COMMAND_PREFIX = '<%= START_CMD %>',
IMAGE = '<%= IMAGE %>',
requirejs = require('webgme').requirejs,
remainingImageCount = 0,
exitCode = null;
requirejs([
'q',
'blob/BlobClient'
], function(
Q,
BlobClient
) {
var url = process.env.ORIGIN_URL || 'http://127.0.0.1:8888',
CACHE_DIR = process.env.DEEPFORGE_WORKER_CACHE || './worker-cache',
protocol = url.split('://').shift(),
address,
port = (url.split(':') || ['80']).pop();
address = url.replace(protocol + '://', '')
.replace(':' + port, '');
// Create CACHE_DIR if it doesn't exist
var prepareCache = function() {
var dirs = CACHE_DIR.replace(/\/$/, '').split('/'),
cacheParent;
dirs.pop();
cacheParent = dirs.join('/');
return makeIfNeeded(cacheParent).then(() => makeIfNeeded(CACHE_DIR));
};
var makeIfNeeded = function(dir) {
var deferred = Q.defer(),
job;
log(`makeIfNeeded: ${JSON.stringify(dir)}`);
fs.lstat(dir, (err, stat) => {
if (err || !stat.isDirectory()) {
fs.mkdir(dir, err => {
if (err) {
return deferred.reject(err);
}
deferred.resolve();
});
} else {
deferred.resolve();
}
});
return deferred.promise;
};
var blobClient = new BlobClient({
server: address,
httpsecure: protocol === 'https',
serverPort: port,
logger: logger
});
var checkFinished = () => {
if (exitCode !== null && remainingImageCount === 0) {
log('finished!');
process.exit(exitCode);
}
};
var uploadImage = function(line) {
var args = line.split(/\s+/),
name = args.slice(2).join(' ').replace(/\s+$/, ''),
filename = 'metadata/' + name + '.png';
// Upload the image from metadata/
remainingImageCount++;
fs.readFile(filename, (err, content) => {
if (err) {
logger.error(`Could not read ${filename}: ${err}`);
return;
}
// Add hash to the image command
log('about to putFile', filename);
blobClient.putFile(filename, content)
.then(hash => {
args.splice(2, 0, hash);
console.log(args.join(' '));
log('printing cmd:', args.join(' '));
--remainingImageCount;
log('finished uploading ' + filename + ' ' + remainingImageCount + ' remain');
checkFinished();
})
.fail(err => logger.error(`${filename} upload failed: ${err}`));
});
};
var onStderr = function(data) {
var text = data.toString();
// Filter out directory label from stack traces
process.stdout.write(text.replace(/\.\.\.\/.*\/(main|deepforge|init).lua/g, '$1'));
};
var onStdout = function(data) {
var lines = data.toString().split('\n'),
result = [],
cmdStart;
// Check for commands...
for (var i = 0; i < lines.length; i++) {
cmdStart = lines[i].indexOf(COMMAND_PREFIX);
if (cmdStart !== -1 && lines[i].indexOf(IMAGE) !== -1) {
uploadImage(lines[i]);
} else {
result.push(lines[i]);
}
}
process.stdout.write(result.join('\n'));
};
var createCacheDir = function(hash) {
var dir = hash.substring(0, 2);
return makeIfNeeded(CACHE_DIR + '/' + dir);
};
var dataCachePath = function(hash) {
var dir = hash.substring(0, 2),
filename = hash.substring(2),
cachePath = `${CACHE_DIR}/${dir}/${filename}`;
// Get the path for data in the cache
return cachePath;
};
var makeSymLink = function(target, src) {
var deferred = Q.defer(),
job;
src = path.resolve(src);
target = path.resolve(target);
fs.stat(src, err => {
if (err.code === 'ENOENT') {
logger.debug(`creating symlink "ln -s ${target} ${src}"`);
job = spawn('ln', ['-s', target, src || '.']);
job.on('exit', code => {
if (code) {
deferred.reject(`Could not create symlink ${target} -> ${src||'.'}`);
return;
}
deferred.resolve();
});
}
deferred.resolve();
});
return deferred.promise;
};
var getData = function(ipath, hashes) {
// Download the data and put it in the given path
var deferred = Q.defer(),
inputName = ipath.split('/')[1],
cachePath = dataCachePath(hashes.cache);
logger.debug(`retrieving ${ipath}`);
fs.lstat(cachePath, (err, cacheStats) => {
// Check if the data exists in the cache
if (!err && cacheStats.isFile()) {
logger.info(`${inputName} already cached. Skipping retrieval from blob`);
return makeSymLink(cachePath, ipath).then(deferred.resolve);
}
createCacheDir(hashes.cache)
.then(() => blobClient.getObject(hashes.req))
.then(buffer => fs.writeFile(cachePath, buffer, (err, result) => {
if (err) {
logger.error('Retrieving ' + ipath + ' failed!');
return deferred.reject(`Could not write to ${ipath}: ${err}`);
}
// Create the symlink
logger.info('Retrieved ' + ipath);
return makeSymLink(cachePath, ipath).then(deferred.resolve);
}))
.fail(err => deferred.reject(`Could not retrieve "${inputName}" (${err})`));
});
return deferred.promise;
};
// Download the large files
var inputData = JSON.parse(fs.readFileSync('./input-data.json')),
inputPaths = Object.keys(inputData);
// Request the data from the blob
prepareCache()
.then(() => Q.all(inputPaths.map(ipath => getData(ipath, inputData[ipath]))))
.then(() => {
// Run 'th init.lua' and merge the stdout, stderr
var job = spawn('th', ['init.lua']);
job.stdout.on('data', onStdout);
job.stderr.on('data', onStderr);
job.on('close', code => {
exitCode = code;
log('script finished w/ exit code:', code);
checkFinished();
});
})
.fail(err => {
console.log(`Data retrieval failed: ${err}`);
process.exit(1);
});
});
+42 -24
Ver Arquivo
@@ -74,6 +74,7 @@ define([
// - keep track if the pipeline has errored
// - if so, don't start any more jobs
this.pipelineError = null;
this.canceled = false;
this.runningJobs = 0;
// metadata records
@@ -103,17 +104,18 @@ define([
// If starting with a pipeline, we will create an Execution first
startPromise = this.createExecution(this.activeNode)
.then(execNode => {
this.logger.debug(`Finished creating execution "${this.core.getAttribute(execNode, 'name')}"`);
this.activeNode = execNode;
});
} else if (this.core.isTypeOf(this.activeNode, this.META.Execution)) {
this.logger.debug('Restarting execution');
startPromise = Q();
} else {
return callback('Current node is not a Pipeline or Execution!', this.result);
}
// Set debug and the final callback
this.debug = true; // this.getCurrentConfig().debug;
this._callback = callback;
this.currentForkName = null;
startPromise
.then(() => this.core.loadSubTree(this.activeNode))
@@ -122,41 +124,29 @@ define([
.filter(n => this.core.getParent(n) === this.activeNode);
this.pipelineName = this.core.getAttribute(this.activeNode, 'name');
this.logger.debug(`Loaded subtree of ${this.pipelineName}. About to build cache`);
this.buildCache(subtree);
this.logger.debug('Parsing execution for job inter-dependencies');
this.parsePipeline(children); // record deps, etc
this.logger.debug('Clearing old results');
return this.clearResults();
})
.then(() => this.executePipeline())
.fail(e => this.logger.error(e));
};
ExecutePipeline.prototype.updateForkName = function () {
var basename = this.pipelineName + '_fork';
return this.project.getBranches().then(branches => {
var names = Object.keys(branches),
name = basename,
i = 2;
while (names.indexOf(name) !== -1) {
name = basename + '_' + i;
i++;
}
this.forkName = name;
});
};
// Override 'save' to prevent race conditions while saving
ExecutePipeline.prototype.save = function (msg) {
// When 'save' is called, it should still finish any current save op
// before continuing
this._currentSave = this._currentSave
.then(() => this.updateForkName())
.then(() => this.updateForkName(this.pipelineName))
.then(() => CreateExecution.prototype.save.call(this, msg))
.then(result => {
var msg;
if (result.status === STORAGE_CONSTANTS.FORKED) {
this.currentForkName = result.forkName;
msg = `"${this.pipelineName}" execution has forked to "${result.forkName}"`;
this.sendNotification(msg);
}
@@ -191,6 +181,8 @@ define([
this.core.setAttribute(this.activeNode, 'status', 'running');
this.logger.info('Setting all jobs status to "pending"');
this.logger.debug(`Making a commit from ${this.currentHash}`);
this.core.setAttribute(this.activeNode, 'startTime', Date.now());
this.core.delAttribute(this.activeNode, 'endTime');
return this.save(`Initializing ${this.pipelineName} for execution`);
};
@@ -289,8 +281,17 @@ define([
this.onPipelineComplete(err);
};
ExecutePipeline.prototype.onOperationCanceled = function(op) {
var job = this.core.getParent(op);
this.core.setAttribute(job, 'status', 'canceled');
this.runningJobs--;
this.logger.debug(`${this.core.getAttribute(job, 'name')} has been canceled`);
this.onPipelineComplete();
};
ExecutePipeline.prototype.onPipelineComplete = function(err) {
var name = this.core.getAttribute(this.activeNode, 'name');
var name = this.core.getAttribute(this.activeNode, 'name'),
msg = `"${this.pipelineName}" `;
if (err) {
this.runningJobs--;
@@ -298,17 +299,34 @@ define([
this.pipelineError = this.pipelineError || err;
if (this.pipelineError && this.runningJobs > 0) {
this.logger.info('Pipeline errored but is waiting for the running ' +
this.logger.debug(`${this.runningJobs} remaining jobs`);
if ((this.pipelineError || this.canceled) && this.runningJobs > 0) {
var action = this.pipelineError ? 'error' : 'cancel';
this.logger.info(`Pipeline ${action}ed but is waiting for the running ` +
'jobs to finish');
return;
}
if (this.currentForkName) {
// notify client that the job has completed
this.sendNotification(`"${this.pipelineName}" execution completed on branch "${this.currentForkName}"`);
}
if (this.pipelineError) {
msg += 'failed!';
} else if (this.canceled) {
msg += 'canceled!';
} else {
msg += 'finished!';
}
this.logger.debug(`Pipeline "${name}" complete!`);
this.core.setAttribute(this.activeNode, 'endTime', Date.now());
this.core.setAttribute(this.activeNode, 'status',
(!this.pipelineError ? 'success' : 'failed'));
(this.pipelineError ? 'failed' : (this.canceled ? 'canceled' : 'success')));
this._finished = true;
this.resultMsg(msg);
this.save('Pipeline execution finished')
.then(() => {
this.result.setSuccess(!this.pipelineError);
@@ -325,7 +343,7 @@ define([
this.logger.info(`About to execute ${readyOps.length} operations`);
// If the pipeline has errored don't start any more jobs
if (this.pipelineError) {
if (this.pipelineError || this.canceled) {
if (this.runningJobs === 0) {
this.onPipelineComplete();
}
+6 -6
Ver Arquivo
@@ -11,17 +11,17 @@
"disableBrowserSideExecution": true,
"configStructure": [
{
"name": "snapshot",
"displayName": "Snapshot",
"description": "Freeze the operation definitions and attributes at current value",
"value": true,
"valueType": "boolean",
"name": "name",
"displayName": "Execution name",
"description": "Optional name for this execution instance",
"value": "",
"valueType": "string",
"readOnly": false
},
{
"name": "debug",
"displayName": "Debug Mode",
"description": "Download all files for each operation",
"description": "Allow for operation editing after creation",
"value": false,
"valueType": "boolean",
"readOnly": false
@@ -1,22 +1,18 @@
/*globals define*/
/*jshint node:true, browser:true*/
/**
* Generated by PluginGenerator 0.14.0 from webgme on Sun Mar 20 2016 16:49:12 GMT-0500 (CDT).
*/
define([
'SimpleNodes/SimpleNodes',
'SimpleNodes/Constants',
'deepforge/layer-args',
'./dimensionality',
'deepforge/utils',
'underscore',
'text!./metadata.json'
], function (
PluginBase,
Constants,
createLayerDict,
dimensionality,
utils,
_,
metadata
) {
@@ -42,11 +38,15 @@ define([
GenerateArchitecture.prototype = Object.create(PluginBase.prototype);
GenerateArchitecture.prototype.constructor = GenerateArchitecture;
GenerateArchitecture.prototype.getTemplateSettings = function () {
return null;
};
GenerateArchitecture.prototype.main = function () {
this.addCustomLayersToMeta();
this.LayerDict = createLayerDict(this.core, this.META);
this.uniqueId = 2;
this._oldTemplateSettings = _.templateSettings;
this.varnames = {};
return PluginBase.prototype.main.apply(this, arguments);
};
@@ -60,25 +60,36 @@ define([
.forEach(node => this.META[this.core.getAttribute(node, 'name')] = node);
};
GenerateArchitecture.prototype.hoist = function (code) {
this.definitions.push(code);
};
GenerateArchitecture.prototype.createOutputFiles = function (tree) {
var layers = tree[Constants.CHILDREN],
//initialLayers,
result = {},
code = 'require \'nn\'\n';
code = '';
this.definitions = [
'require \'nn\'',
'require \'rnn\''
];
//initialLayers = layers.filter(layer => layer[Constants.PREV].length === 0);
// Add an index to each layer
layers.forEach((l, index) => l[INDEX] = index);
// Define custom layers
if (this.getCurrentConfig().standalone) {
this.logger.debug('Generating layer definitions');
code += this.genLayerDefinitions(layers);
}
this.logger.debug('Generating architecture code...');
code += this.genArchCode(layers);
this.logger.debug('Prepending hoisted code...');
code = this.definitions.join('\n') + '\n' + code;
result[tree.name + '.lua'] = code;
_.templateSettings = this._oldTemplateSettings; // FIXME: Fix this in SimpleNodes
this.logger.debug(`Finished generating ${tree.name}.lua`);
return result;
};
@@ -89,10 +100,38 @@ define([
].join('\n');
};
GenerateArchitecture.prototype.genRawArchCode = function (layers, name) {
var result = '';
if (layers.length > 1) {
return this.createSequential(layers[0], name).code;
} else if (name) {
result = `\nlocal ${name} = `;
}
result += this.createLayer(layers[0]);
return result;
};
GenerateArchitecture.prototype.getVarName = function (base) {
// Check "this.varnames"
var name = base,
i = 2;
while (this.varnames[name]) {
name = base + '_' + (i++);
}
this.varnames[name] = true;
return name;
};
GenerateArchitecture.prototype.createLayer = function (layer) {
var args = this.createArgString(layer);
return `nn.${layer.name}${args}`;
};
GenerateArchitecture.prototype.createSequential = function (layer, name) {
var next = layer[Constants.NEXT][0],
args,
template,
snippet,
snippets,
code = `\nlocal ${name} = nn.Sequential()`,
@@ -107,10 +146,8 @@ define([
next = layer; // the given layer will be added by the caller
break;
} else { // add the given layer
args = this.createArgString(layer);
template = _.template(name + ':add(nn.{{= name }}' + args + ')');
snippet = template(layer);
code += '\n' + snippet;
snippet = this.createLayer(layer);
code += `\n${name}:add(${snippet})`;
}
@@ -119,7 +156,7 @@ define([
this.logger.debug(`detected fork of size ${layer[Constants.NEXT].length}`);
snippets = layer[Constants.NEXT].map(nlayer =>
this.createSequential(nlayer, 'net_'+(this.uniqueId++)));
this.createSequential(nlayer, this.getVarName('net')));
code += '\n' + snippets.map(snippet => snippet.code).join('\n');
// Make sure all snippets end at the same concat node
@@ -157,7 +194,7 @@ define([
// merge the elements in the group
if (snippets.length) { // prepare next iteration
result = this.createSequential(next, 'net_'+(this.uniqueId++));
result = this.createSequential(next, this.getVarName('net'));
code += result.code;
group = [result];
this.logger.debug('updating group ('+ snippets.length+ ' left)');
@@ -177,11 +214,65 @@ define([
};
};
GenerateArchitecture.prototype.getValue = function (arg, layer) {
var content = layer[arg];
if (typeof content === 'object') { // layer as arg
if (content[Constants.CHILDREN].length) {
// Generate the code for the children of layer[arg]
var name = this.getVarName(utils.abbr(arg)),
layers;
this.logger.debug(`Adding layer arg for ${arg} (${layer.name})`);
try {
layers = this.genRawArchCode(layer[arg][Constants.CHILDREN], name);
} catch (e) {
this.logger.error(`Layer arg creation failed: ${e}`);
return null;
}
// hoist layer definitions to the top of the file
this.hoist(layers);
return name;
} else {
return null;
}
}
return content;
};
GenerateArchitecture.prototype.createArgString = function (layer) {
return '(' + this.LayerDict[layer.name]
.map(arg => layer[arg.name])
var setters = this.LayerDict[layer.name].setters,
setterNames = Object.keys(this.LayerDict[layer.name].setters),
base = layer[Constants.BASE],
desc,
fn,
layerCode;
this.logger.debug(`Creating arg string for ${layer.name}`);
layerCode = '(' + this.LayerDict[layer.name].args
.map(arg => this.getValue(arg.name, layer))
.filter(GenerateArchitecture.isSet)
.join(', ') + ')';
.join(', ') + ')';
// Add any setters
// For each setter, check if it has been changed (and needs to be set)
for (var i = setterNames.length; i--;) {
desc = setters[setterNames[i]];
if (desc.setterType === 'const') {
// if the value is not the default, add the given fn
if (layer[setterNames[i]] !== base[setterNames[i]]) {
fn = desc.setterFn[layer[setterNames[i]]];
layerCode += `:${fn}()`;
}
} else if (layer[setterNames[i]] !== null && layer[setterNames[i]] !== undefined) {
fn = desc.setterFn;
layerCode += `:${fn}(${layer[setterNames[i]]})`;
}
}
this.logger.debug(`Created nn.${layer.name}${layerCode}`);
return layerCode;
};
GenerateArchitecture.isSet = function (value) {
@@ -1,52 +0,0 @@
/* globals define */
define([
'SimpleNodes/Constants',
'deepforge/lua'
], function(
Constants,
luajs
) {
'use strict';
var dimensionality = function(node) {
var transform = node.dimensionalityTransform;
return dimensionality[transform](node);
};
// If 'same', return the input dimensions
dimensionality.same = function(node) {
var prev = node[Constants.PREV][0];
return dimensionality(prev);
};
dimensionality.custom = function(node) {
var luaFn = node.calculateDimensionality,
cxt = luajs.newContext(),
layer, // lua layer
bin,
dims;
cxt.loadStdLib();
// - cross compile to js
bin = cxt.loadString(luaFn);
bin(); // load the calc fn to global context
// Create the layer
layer = new luajs.types.LuaTable();
var attrs = Object.keys(node).filter(attr => attr.indexOf('_') !== 0);
for (var i = attrs.length; i--;) {
layer.set(attrs[i], node[attrs[i]]);
}
cxt._G.set('layer', layer);
// call the function with layer and input dimensions
bin = cxt.loadString('return calcDims(layer)');
dims = bin()[0]; // TODO: Add support for multiple dimensions
// TODO: return a fn if it depends on the previous value
return dims;
};
return dimensionality;
});
+21 -15
Ver Arquivo
@@ -1,18 +1,12 @@
/*globals define*/
/*jshint node:true, browser:true*/
/**
* Generated by PluginGenerator 0.14.0 from webgme on Thu Mar 10 2016 04:16:02 GMT-0600 (CST).
*/
define([
'deepforge/layer-args',
'deepforge/lua',
'./nn',
'plugin/PluginBase',
'text!./metadata.json'
], function (
LayerDict,
luajs,
createNNSearcher,
PluginBase,
@@ -55,6 +49,8 @@ define([
return callback('Torch code not provided.', this.result);
}
this.addCustomLayersToMeta();
this.blobClient.getMetadata(srcHash)
.then(mdata => { // Create the new model
// If the current node is an architecture, assume we are just extending it
@@ -78,11 +74,10 @@ define([
this.loadNNMock();
// Cross compile to js and run
src = 'require \'nn\'\n' + src; // guarantee it loads nn
this.bin = this.context.loadString(src);
this.bin();
this.afterExecution();
return this.save('ImportTorch updated model.');
})
.then(() => { // changes saved successfully
@@ -97,6 +92,22 @@ define([
);
};
ImportTorch.prototype.addCustomLayersToMeta = function () {
// Add custom layers to the metamodel
var metanodes = this.core.getAllMetaNodes(this.rootNode),
name;
Object.keys(metanodes).map(id => metanodes[id])
.filter(node => this.core.isTypeOf(node, this.META.Layer))
.forEach(layer => {
name = this.core.getAttribute(layer, 'name');
if (!this.META[name]) {
this.logger.debug(`Adding ${name} to the meta`);
this.META[name] = layer;
}
});
};
// Create the 'nn' shim and add it to the global context
ImportTorch.prototype.loadNNMock = function () {
// This needs a refactor...
@@ -107,15 +118,10 @@ define([
this.context._G.get('package').set('searchers', [function(name) {
if (name === 'nn') {
return lib;
} else {
return () => {};
}
}]);
// Some scripts don't include `require 'nn'`. I may have to add the
// "nn" package to the global scope...
};
ImportTorch.prototype.afterExecution = function () {
// TODO
};
return ImportTorch;
+148 -17
Ver Arquivo
@@ -7,7 +7,7 @@ define([
], function(
createLayerDict,
assert,
luajs
lua
) {
'use strict';
@@ -19,7 +19,8 @@ define([
LayerDict = createLayerDict(core, META),
helpers = context.__helpers,
oldSet = helpers.__set,
isSetting = false;
isSetting = false,
connsFrom = {};
// Override the helper's '__set' method to detect
// if the code is in the middle of a "set".
@@ -29,24 +30,68 @@ define([
isSetting = false;
};
var stringify = function(table) {
var strings = table.array.map(val => {
if (val instanceof lua.types.LuaTable) {
return stringify(val);
} else {
return val;
}
});
return '{' + strings.join(', ') + '}';
};
var allConnectedTo = function(current) {
var connectedIds = {},
node,
id;
while (current.length) {
node = current.shift();
id = core.getGuid(node);
if (connectedIds[id]) {
continue;
}
connectedIds[id] = node;
if (connsFrom[id]) {
current = current.concat(connsFrom[id]);
}
}
// Return an array of all things connected to the
// given node
return Object.keys(connectedIds).map(key => connectedIds[key]);
};
var connect = function(src, dst) {
var conn = core.createNode({
var conn,
id;
conn = core.createNode({
parent: parent,
base: META.Connection
});
core.setPointer(conn, 'src', src);
core.setPointer(conn, 'dst', dst);
// Record this
id = core.getGuid(src);
if (!connsFrom[id]) {
connsFrom[id] = [];
}
connsFrom[id].push(conn, dst);
};
// nn drawing library
var Layer = function(base, attrs, args) {
this._base = base;
this._attrs = attrs;
for (var i = 0; i < attrs.length; i++) {
this[attrs[i].name] = args[i];
}
// inputs/outputs used for being added to containers
this._values = args;
this._cachedNode = null;
this._inputs = [this._node()];
this._outputs = [this._node()];
@@ -55,6 +100,10 @@ define([
Layer.prototype._node = function() {
var name,
node,
nodes,
cntr,
layer,
cntrName,
value;
if (this._cachedNode) {
@@ -70,16 +119,42 @@ define([
for (var i = this._attrs.length; i--;) {
name = this._attrs[i].name;
value = this[name];
if ((typeof value) === 'object') {
// special lua.js object
value = value.valueOf();
}
value = this._values[i];
// TODO: Update this to check if inferred and the value matches
// our inferred value. If so, skip it
if (value !== undefined/*&& !this._attrs[i].infer*/) {
core.setAttribute(node, name, value);
if (value instanceof lua.types.LuaTable) {
layer = value.get('_node');
if (layer) { // layer arg!
// add all the inputs, outputs (and connected elements) to
// be in an "Architecture" node in the current node
cntr = core.createNode({
base: META.Architecture,
parent: node
});
cntrName = `${name} (${this._base})`;
logger.debug(`Naming layer arg ${cntrName}`);
core.setAttribute(cntr, 'name', cntrName);
// Move all connecting elements of the value to
// the cntr
nodes = allConnectedTo(layer._inputs.concat(layer._outputs));
for (var j = nodes.length; j--;) {
core.moveNode(nodes[j], cntr);
}
core.setPointer(node, name, cntr);
logger.debug(`Moving ${nodes.length} to ${name}(${this._base})`);
} else { // Something like {1, 2, 3}
value = stringify(value);
logger.debug(`Setting ${name} to ${value} (${this._base})`);
core.setAttribute(node, name, value);
}
} else { // attribute value
if ((typeof value) === 'object') {
// special lua.js object
value = value.valueOf();
}
if (value !== undefined) {
logger.debug(`Setting ${name} to ${value} (${this._base})`);
core.setAttribute(node, name, value);
}
}
}
@@ -87,6 +162,13 @@ define([
return node;
};
Layer.prototype._setAttribute = function(name, self, value) {
var node = this._node();
logger.info(`Setting ${name} to ${value}`);
core.setAttribute(node, name, value);
return self;
};
// Each container will have `inputs` and `outputs`
var Container = function() {
// inputs and outputs are webgme nodes
@@ -153,16 +235,59 @@ define([
Sequential: Sequential
};
var getValue = function(txt) {
if (txt === 'true') {
return true;
}
if (txt === 'false') {
return false;
}
if (/^\d+$/.test(txt)) {
return +txt;
}
return txt;
};
var addSetterMethods = function(table, attr, dict) {
var desc = dict[attr],
layer = table.get('_node'),
vals,
value,
fn;
if (desc.setterType === 'arg') {
fn = desc.setterFn;
table.set(fn, layer._setAttribute.bind(layer, attr));
} else {
vals = Object.keys(desc.setterFn);
for (var i = vals.length; i--;) {
fn = desc.setterFn[vals[i]];
value = getValue(vals[i]);
table.set(fn, layer._setAttribute.bind(layer, attr, table, value));
}
}
};
var CreateLayer = function(type) {
var res = luajs.newContext()._G,
var res = lua.newContext()._G,
attrs = [].slice.call(arguments, 1),
ltGet = luajs.types.LuaTable.prototype.get,
ltGet = lua.types.LuaTable.prototype.get,
setters = [],
args = [],
node;
if (LayerDict[type]) {
args = LayerDict[type].args;
setters = Object.keys(LayerDict[type].setters);
}
if (LAYERS[type]) {
node = new LAYERS[type](LayerDict[type] || [], attrs);
node = new LAYERS[type](args, attrs);
} else { // Call generic Layer with type name
node = new Layer(type, LayerDict[type] || [], attrs);
node = new Layer(type, args, attrs);
}
res.set('_node', node);
@@ -178,6 +303,12 @@ define([
}
}
// add setters
// look up the setters
for (var i = setters.length; i--;) {
addSetterMethods(res, setters[i], LayerDict[type].setters);
}
// Override get
res.get = function noNilGet(value) {
var result = ltGet.call(this, value);
@@ -197,7 +328,7 @@ define([
}
// TODO: Create the nn object
var nn = luajs.newContext()._G,
var nn = lua.newContext()._G,
names = Object.keys(LayerDict);
for (var i = names.length; i--;) {
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
Arquivo binário não exibido.
+12
Ver Arquivo
@@ -88,5 +88,17 @@
"title": "LineGraph",
"panel": "panels/LineGraph/LineGraphPanel",
"DEBUG_ONLY": false
},
{
"id": "ImageViewer",
"title": "ImageViewer",
"panel": "panels/ImageViewer/ImageViewerPanel",
"DEBUG_ONLY": false
},
{
"id": "ExecutionIndex",
"title": "ExecutionIndex",
"panel": "panels/ExecutionIndex/ExecutionIndexPanel",
"DEBUG_ONLY": false
}
]
@@ -2,12 +2,14 @@
/*jshint browser: true*/
define([
'deepforge/Constants',
'deepforge/globals',
'panels/EasyDAG/EasyDAGControl',
'js/NodePropertyNames',
'js/Utils/ComponentSettings',
'underscore'
], function (
Constants,
DeepForge,
EasyDAGControl,
nodePropertyNames,
@@ -38,6 +40,7 @@ define([
_.extend(ArchEditorControl.prototype, EasyDAGControl.prototype);
ArchEditorControl.prototype.TERRITORY_RULE = {children: 1};
ArchEditorControl.prototype.DEFAULT_DECORATOR = 'LayerDecorator';
ArchEditorControl.prototype.getComponentId = function() {
return 'ArchEditor';
};
@@ -59,12 +62,24 @@ define([
if (!desc.isConnection) {
var allAttrs = desc.attributes,
names = Object.keys(allAttrs),
schema;
ctorInfo = desc.attributes[Constants.CTOR_ARGS_ATTR],
ctorAttrs = ctorInfo ? ctorInfo.value.split(','): [],
schema,
i;
desc.attributes = {};
for (var i = names.length; i--;) {
// add ctor attributes
for (i = 0; i < ctorAttrs.length; i++) {
if (allAttrs[ctorAttrs[i]]) { // (not a ref to a layer)
desc.attributes[ctorAttrs[i]] = allAttrs[ctorAttrs[i]];
}
}
for (i = names.length; i--;) {
// check if it is a setter
schema = this._client.getAttributeSchema(id, names[i]);
if (names[i] === 'name' || schema.hasOwnProperty('argindex')) {
if (names[i] === 'name' || schema.setterType) {
desc.attributes[names[i]] = allAttrs[names[i]];
}
}
@@ -163,7 +178,7 @@ define([
ArchEditorControl.prototype.getCreateNewDecorator = function() {
return this._client.decoratorManager.getDecoratorForWidget(
'EllipseDecorator',
'LayerDecorator',
'EasyDAG'
);
};
@@ -3,10 +3,12 @@
define([
'panels/TextEditor/TextEditorControl',
'deepforge/lua',
'underscore',
'text!./DefaultCodeTemplate.ejs'
], function (
TextEditorControl,
lua,
_,
CODE_TEMPLATE
) {
@@ -53,19 +55,95 @@ define([
match = returned.match(/[a-zA-Z0-9_]+/),
node = this._client.getNode(id),
nodeName = node.getAttribute('name'),
name;
baseName = null,
basePath,
name,
ast;
if (match) {
name = match[0];
}
// Check if the base needs to be updated
try {
ast = lua.parser.parse(text);
lua.codegen.traverse(curr => {
// Check for inheritance of the given type
if (curr.type === 'expr.call') {
var object = curr.func.self.val,
method = curr.func.key.val,
child,
base;
if (object === 'torch' && method === 'class') {
child = curr.args[0];
base = curr.args[1];
// If the first argument is the given class, get the base
if (child.type === 'const.string' && child.val === name) {
if (base && base.type === 'const.string') {
baseName = base.val;
}
}
}
}
})(ast);
// Get the base path from the base name
basePath = this.getBasePathFromName(baseName);
if (!basePath) {
this._logger.warn(`Could not find base type matching the name ${baseName}`);
}
} catch(e) {
this._logger.warn(`Invalid lua code. Parser failed: ${e}`);
}
this._client.startTransaction(`Updating class "${name || nodeName}"`);
if (name) {
this._client.setAttributes(id, 'name', name);
}
if (basePath) {
this._client.setBase(id, basePath);
} else { // Set base back to 'Complex'
while (node && (node.getAttribute('name') !== 'Complex' ||
node.isAbstract() !== true)) {
node = this._client.getNode(node.getBaseId());
}
if (node) { // node is the base class type
this._client.setBase(id, node.getId());
} else {
this._logger.warn(`Could not find the base class type from ${id}`);
}
}
TextEditorControl.prototype.saveTextFor.call(this, id, text);
this._client.completeTransaction();
};
ClassCodeEditorControl.prototype.getBasePathFromName = function (baseName) {
var metanodes = this._client.getAllMetaNodes(),
nameMatches = [],
classNode,
i;
for (i = metanodes.length; i--;) {
if (metanodes[i].getAttribute('name') === baseName) {
nameMatches.push(metanodes[i]);
}
if (metanodes[i].getAttribute('name') === 'Complex') {
classNode = metanodes[i];
}
}
for (i = nameMatches.length; i--;) {
if (this._client.isTypeOf(nameMatches[i].getId(), classNode.getId())) {
return nameMatches[i].getId();
}
}
return null;
};
return ClassCodeEditorControl;
});
@@ -0,0 +1,377 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'deepforge/utils'
], function (
CONSTANTS,
utils
) {
'use strict';
var ExecutionIndexControl;
ExecutionIndexControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
this._embedded = options.embedded;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this.displayedExecutions = {};
this._linesForExecution = {};
this._lineToExec = {};
this._pipelineNames = {};
this.abbrToId = {};
this.abbrFor = {};
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
ExecutionIndexControl.prototype._initWidgetEventHandlers = function () {
this._widget.setExecutionDisplayed = this.setExecutionDisplayed.bind(this);
};
ExecutionIndexControl.prototype.setExecutionDisplayed = function (id, bool) {
var lines = this._linesForExecution[id] || [],
otherLines,
wasMultiLine = this.displayedExecCount() > 1,
isMultiLine;
this._logger.info(`setting execution ${id} to ${bool ? 'displayed' : 'hidden'}`);
this.displayedExecutions[id] = bool;
// If we just crossed the multi line threshold, then update all the lines
isMultiLine = this.displayedExecCount() > 1;
if (isMultiLine !== wasMultiLine) {
// Refresh the other lines visible
otherLines = Object.keys(this.displayedExecutions)
.filter(eId => this.displayedExecutions[eId] && (eId !== id))
.map(id => this._linesForExecution[id])
.reduce((l1, l2) => l1.concat(l2), []);
this._updateLines(otherLines, false);
this._updateLines(otherLines, true);
}
this._updateLines(lines, bool);
};
ExecutionIndexControl.prototype._updateLines = function (lines, added) {
var action = added ? 'addNode' : 'removeNode';
// If removing, just get the ids
lines = !added ? lines : lines.map(line => this._getObjectDescriptor(line));
// update the given lines
for (var i = lines.length; i--;) {
this._widget[action](lines[i]);
}
};
ExecutionIndexControl.prototype.clearTerritory = function () {
if (this._territoryId) {
this._client.removeUI(this._territoryId);
this._territoryId = null;
}
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
ExecutionIndexControl.prototype.selectedObjectChanged = function (nodeId) {
var self = this;
self._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
self.clearTerritory();
self._currentNodeId = nodeId;
if (typeof self._currentNodeId === 'string') {
// Create a territory for the executions
self._selfPatterns = {};
self._territoryId = self._client.addUI(self, function (events) {
self._eventCallback(events);
});
// Update the territory
self._selfPatterns[nodeId] = {children: 4};
self._client.updateTerritory(self._territoryId, self._selfPatterns);
}
};
ExecutionIndexControl.prototype.getUniqAbbreviation = function(desc) {
// Get a unique abbreviation for the given execution
var base = utils.abbr(desc.name).toLowerCase(),
abbr = base,
oldAbbr = this.abbrFor[desc.id],
i = 2;
// Make sure it is unique!
while (this.abbrToId[abbr] && this.abbrToId[abbr] !== desc.id) {
abbr = base + i;
i++;
}
if (oldAbbr !== undefined) { // updating abbr
delete this.abbrToId[oldAbbr];
}
this.abbrToId[abbr] = desc.id;
this.abbrFor[desc.id] = abbr;
return abbr;
};
// This next function retrieves the relevant node information for the widget
ExecutionIndexControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
childIds,
desc,
base,
type;
if (node) {
base = this._client.getNode(node.getBaseId());
type = base.getAttribute('name');
desc = {
id: node.getId(),
type: type,
name: node.getAttribute('name')
};
if (type === 'Execution') {
desc.status = node.getAttribute('status');
desc.originTime = node.getAttribute('createdAt');
desc.originId = node.getPointer('origin').to;
desc.pipelineName = this._pipelineNames[desc.originId];
desc.startTime = node.getAttribute('startTime');
desc.endTime = node.getAttribute('endTime');
this._logger.debug(`Looking up pipeline name for ${desc.name}: ${desc.pipelineName}`);
// Add the (unique) abbreviation of the execution!
desc.abbr = this.getUniqAbbreviation(desc);
// Create a territory for this origin and update it!
this._selfPatterns[desc.originId] = {children: 0};
setTimeout(() => this._client.updateTerritory(this._territoryId, this._selfPatterns), 0);
} else if (type === 'Line') {
desc = this.getLineDesc(node);
} else if (type === 'Pipeline') {
desc.execs = node.getMemberIds('executions');
this._pipelineNames[desc.id] = desc.name;
} else if (type === 'Graph') {
childIds = node.getChildrenIds();
desc.lines = childIds.map(id => {
var n = this._client.getNode(id);
return this.getLineDesc(n);
});
}
}
return desc;
};
ExecutionIndexControl.prototype.getLineDesc = function (node) {
var id = node.getId(),
graphId = node.getParentId(),
jobId = this._client.getNode(graphId).getParentId(),
execId = this._client.getNode(jobId).getParentId(),
points,
desc;
points = node.getAttribute('points').split(';')
.filter(data => !!data) // remove any ''
.map(pair => {
var nums = pair.split(',').map(num => parseFloat(num));
return {
x: nums[0],
y: nums[1]
};
});
desc = {
id: id,
execId: execId,
lineName: node.getAttribute('name'),
name: node.getAttribute('name'),
type: 'line',
points: points
};
if (!this._lineToExec[id]) {
// Update records
if (!this._linesForExecution[execId]) {
this._linesForExecution[execId] = [];
}
this._linesForExecution[execId].push(id);
this._lineToExec[id] = execId;
}
// If there are multiple executions, add the exec's abbr
var displayedCnt = this.displayedExecCount(),
execAbbr;
if (displayedCnt > 1) {
execAbbr = this.abbrFor[execId] || this._getObjectDescriptor(execId).abbr;
desc.name = `${desc.name} (${execAbbr})`;
}
return desc;
};
/* * * * * * * * Node Event Handling * * * * * * * */
ExecutionIndexControl.prototype._eventCallback = function (events) {
var event;
events = events.filter(event => event.eid !== this._currentNodeId);
this._logger.debug('received \'' + events.length + '\' events');
for (var i = events.length; i--;) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
this._onLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
break;
}
}
this._logger.debug('finished processing events!');
};
ExecutionIndexControl.prototype._onLoad = function (gmeId) {
var desc = this._getObjectDescriptor(gmeId);
this._logger.debug(`Loading node of type ${desc.type}`);
if (desc.type === 'Execution') {
this._logger.debug('Adding node to widget...');
this._logger.debug('desc:', desc);
this._widget.addNode(desc);
} else if (desc.type === 'line' && this.isLineDisplayed(desc)) {
this._widget.addNode(desc);
} else if (desc.type === 'Pipeline') {
this.updatePipelineNames(desc);
}
};
ExecutionIndexControl.prototype._onUpdate = function (gmeId) {
var desc = this._getObjectDescriptor(gmeId);
if (desc.type === 'Execution') {
this._widget.updateNode(desc);
} else if (desc.type === 'line' && this.isLineDisplayed(desc)) {
this._widget.updateNode(desc);
} else if (desc.type === 'Pipeline') {
this.updatePipelineNames(desc);
}
};
ExecutionIndexControl.prototype.updatePipelineNames = function (desc) {
// Get all associated executions and update their pipeline name
this._logger.debug('updating pipeline name for ' + desc.execs.join(', '));
for (var i = desc.execs.length; i--;) {
this._widget.updatePipelineName(desc.execs[i], desc.name);
}
if (desc.execs.length === 0) {
// Executions have been deleted - no longer relevant
this._logger.debug('pipeline has 0 executions... removing it', desc.id);
delete this._selfPatterns[desc.id];
delete this._pipelineNames[desc.id];
}
};
ExecutionIndexControl.prototype._onUnload = function (id) {
var execId = this._lineToExec[id],
abbr;
if (execId) { // it is a line
delete this._lineToExec[id];
for (var k = this._linesForExecution[execId].length; k--;) {
if (this._linesForExecution[execId][k] === id) {
this._linesForExecution[execId].splice(k, 1);
break;
}
}
}
if (this.abbrFor[id]) {
abbr = this.abbrFor[id];
delete this.abbrFor[id];
delete this.abbrToId[abbr];
}
this._widget.removeNode(id);
};
ExecutionIndexControl.prototype.isLineDisplayed = function (line) {
// lines are only displayed if their execution is checked
return this.displayedExecutions[line.execId];
};
ExecutionIndexControl.prototype.displayedExecCount = function () {
return Object.keys(this.displayedExecutions)
.map(id => this.displayedExecutions[id])
.filter(shown => shown).length;
};
ExecutionIndexControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId === activeObjectId) {
// The same node selected as before - do not trigger
} else {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ExecutionIndexControl.prototype.destroy = function () {
this._detachClientEventListeners();
this.clearTerritory();
};
ExecutionIndexControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged, this);
}
};
ExecutionIndexControl.prototype._detachClientEventListeners = function () {
if (!this._embedded) {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
}
};
ExecutionIndexControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
ExecutionIndexControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return ExecutionIndexControl;
});
@@ -0,0 +1,93 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/PanelBase/PanelBase',
'js/PanelManager/IActivePanel',
'widgets/ExecutionIndex/ExecutionIndexWidget',
'./ExecutionIndexControl'
], function (
PanelBase,
IActivePanel,
ExecutionIndexWidget,
ExecutionIndexControl
) {
'use strict';
var ExecutionIndexPanel;
ExecutionIndexPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBase.OPTIONS.LOGGER_INSTANCE_NAME] = 'ExecutionIndexPanel';
options[PanelBase.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBase.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBase
_.extend(ExecutionIndexPanel.prototype, PanelBase.prototype);
_.extend(ExecutionIndexPanel.prototype, IActivePanel.prototype);
ExecutionIndexPanel.prototype._initialize = function () {
//set Widget title
this.widget = new ExecutionIndexWidget(this.logger, this.$el);
this.control = new ExecutionIndexControl({
logger: this.logger,
client: this._client,
embedded: this._embedded,
widget: this.widget
});
this.onActivate();
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ExecutionIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBase.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
ExecutionIndexPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ExecutionIndexPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBase.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
ExecutionIndexPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
ExecutionIndexPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return ExecutionIndexPanel;
});
@@ -1,15 +1,14 @@
/*globals define, WebGMEGlobal */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 24 2016 10:15:19 GMT-0500 (CDT).
*/
define([
'js/Constants',
'deepforge/Constants',
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/PipelineControl',
'underscore'
], function (
GME_CONSTANTS,
CONSTANTS,
EasyDAGControl,
PipelineControl,
@@ -62,7 +61,7 @@ define([
return;
}
if (event.etype === CONSTANTS.TERRITORY_EVENT_UNLOAD) {
if (event.etype === GME_CONSTANTS.TERRITORY_EVENT_UNLOAD) {
this.originId = null;
this._widget.onOriginDeleted();
} else {
@@ -90,6 +89,65 @@ define([
};
};
ExecutionViewControl.prototype._getObjectDescriptor = function(id) {
var desc = PipelineControl.prototype._getObjectDescriptor.call(this, id),
childrenIds,
node,
opId;
// If it is a job, add the operation attributes
if (this.hasMetaName(id, 'Job')) {
node = this._client.getNode(id);
childrenIds = node.getChildrenIds();
opId = childrenIds.find(id => this.hasMetaName(id, 'Operation'));
desc.opAttributes = {};
if (opId) {
var opNode = this._client.getNode(opId),
attrs,
allAttrs = {},
hiddenAttrs = [
CONSTANTS.LINE_OFFSET,
'code',
'name'
],
i;
opNode.getValidAttributeNames().concat(opNode.getAttributeNames())
.forEach(attr => allAttrs[attr] = true);
// Remove skip values
hiddenAttrs.forEach(attr => delete allAttrs[attr]);
attrs = Object.keys(allAttrs);
for (i = attrs.length; i--;) {
desc.opAttributes[attrs[i]] = {
name: attrs[i],
value: opNode.getAttribute(attrs[i]),
type: 'string'
};
}
// Pointers
var allPtrs = {},
ptrs;
opNode.getValidPointerNames().concat(opNode.getPointerNames())
.filter(ptr => ptr !== 'base')
.forEach(ptr => allPtrs[ptr] = true);
ptrs = Object.keys(allPtrs);
for (i = ptrs.length; i--;) {
desc.pointers[ptrs[i]] = opNode.getPointer(ptrs[i]).to;
}
} else {
this.logger.error(`Job "${desc.name}" (${id}) is missing an operation!`);
}
}
return desc;
};
ExecutionViewControl.prototype._onLoad = function(id) {
var desc = this._getObjectDescriptor(id);
@@ -1,13 +1,16 @@
/*globals DeepForge, define, $, Materialize, WebGMEGlobal*/
/*globals define, $, WebGMEGlobal*/
// These are actions defined for specific meta types. They are evaluated from
// the context of the ForgeActionButton
define([
'panel/FloatingActionButton/styles/Materialize',
'q',
'js/RegistryKeys',
'deepforge/globals'
], function(
Materialize,
Q,
REGISTRY_KEYS
REGISTRY_KEYS,
DeepForge
) {
var FILE_UPLOAD_INPUT = $('<input type="file" />');
@@ -103,6 +106,7 @@ define([
name: `Return to ${fromType}`,
icon: 'input',
priority: 2,
color: 'teal',
filter: () => {
return DeepForge.last[fromType];
},
@@ -112,6 +116,7 @@ define([
name: `Delete ${type} Definition`,
icon: 'delete',
priority: 1,
color: 'red',
action: function() {
// Delete and go to the last pipeline?
var node = this.client.getNode(this._currentNodeId),
@@ -134,13 +139,19 @@ define([
}
];
var makeRestartButton = function(name, pluginId) {
var makeRestartButton = function(name, pluginId, hotkeys) {
return {
name: 'Restart ' + name,
icon: 'replay',
priority: 1000,
color: 'red',
hotkey: hotkeys && 'shift enter',
filter: function() {
// Only show if stopped!
return !this.isRunning();
},
action: function(event) {
this.runExecutionPlugin(pluginId, event.shiftKey);
this.runExecutionPlugin(pluginId, {useSecondary: event.shiftKey});
}
};
};
@@ -215,9 +226,47 @@ define([
icon: 'play_for_work',
priority: 1,
href: download.execFiles
},
// Stop execution button
{
name: 'Stop Current Job',
icon: 'stop',
priority: 1001,
filter: function() {
return this.isRunning();
},
action: function() {
this.stopJob();
}
}
],
Execution: [
makeRestartButton('Execution', 'ExecutePipeline', true),
// Stop execution button
{
name: 'Stop Running Execution',
icon: 'stop',
priority: 1001,
hotkey: 'shift enter',
filter: function() {
return this.isRunning();
},
action: function() {
// Stop every running job
var execNode = this.client.getNode(this._currentNodeId),
jobIds = execNode.getChildrenIds(),
msg = `Canceling ${execNode.getAttribute('name')} execution`;
this.client.startTransaction(msg);
jobIds.map(id => this.client.getNode(id))
.filter(job => this.isRunning(job)) // get running jobs
.forEach(job => this.stopJob(job)); // stop them
this.client.setAttributes(execNode.getId(), 'status', 'canceled');
this.client.completeTransaction();
}
}
],
Execution: [makeRestartButton('Execution', 'ExecutePipeline')],
Pipeline: [
{
name: 'Create new node',
@@ -1,4 +1,4 @@
/*globals DeepForge, $, Materialize, define, _ */
/*globals $, window, define, _ */
/*jshint browser: true*/
define([
@@ -7,6 +7,7 @@ define([
'panel/FloatingActionButton/FloatingActionButton',
'deepforge/viz/PipelineControl',
'deepforge/viz/NodePrompter',
'deepforge/viz/Execute',
'./Actions',
'widgets/EasyDAG/AddNodeDialog',
'js/RegistryKeys',
@@ -20,12 +21,14 @@ define([
PluginButton,
PipelineControl,
NodePrompter,
Execute,
ACTIONS,
AddNodeDialog,
REGISTRY_KEYS,
META_CONSTANTS,
Q,
PluginConfig
PluginConfig,
DeepForge
) {
'use strict';
@@ -39,6 +42,8 @@ define([
logger: this.logger.fork('BlobClient')
});
Execute.call(this, this.client, this.logger);
this.initializeKeyListener();
this.logger.debug('ctor finished');
};
@@ -46,9 +51,46 @@ define([
_.extend(
ForgeActionButton.prototype,
PluginButton.prototype,
Execute.prototype,
PipelineControl.prototype
);
ForgeActionButton.prototype.initializeKeyListener = function() {
// add key listener to parent?
this.oldOnKeyDown = document.body.onkeydown;
document.onkeydown = event => {
var keys = String.fromCharCode(event.which) || '',
names = Object.keys(this.buttons),
btn,
name;
// Simple button detection
if (event.which === 13) {
keys = 'enter';
}
if (event.shiftKey) {
keys = 'shift ' + keys;
}
for (var i = names.length; i--;) {
name = names[i];
btn = this.buttons[name];
if (btn.hotkey && btn.hotkey === keys) {
btn.action.call(this, event);
}
}
if (this.oldOnKeyDown) {
this.oldOnKeyDown(event);
}
};
};
ForgeActionButton.prototype.destroy = function() {
PluginButton.prototype.destroy.call(this);
PipelineControl.prototype.destroy.call(this);
document.body.onclick = this.oldOnKeyDown;
};
ForgeActionButton.prototype.findActionsFor = function(nodeId) {
var node = this.client.getNode(nodeId),
base = this.client.getNode(node.getMetaTypeId()),
@@ -60,7 +102,7 @@ define([
if (!base) { // must be ROOT or FCO
basename = node.getAttribute('name') || 'ROOT_NODE';
actions = (ACTIONS[basename] || [])
.filter(action => !action.filter || action.filter());
.filter(action => !action.filter || action.filter.call(this));
return actions;
}
@@ -69,7 +111,7 @@ define([
base = this.client.getNode(base.getBaseId());
actions = ACTIONS[basename];
if (actions) {
actions = actions.filter(action => !action.filter || action.filter());
actions = actions.filter(action => !action.filter || action.filter.call(this));
}
}
@@ -321,21 +363,5 @@ define([
}
};
ForgeActionButton.prototype.runExecutionPlugin = function(pluginId, useSecondary) {
var context = this.client.getCurrentPluginContext(pluginId),
name = this.client.getNode(this._currentNodeId).getAttribute('name'),
method;
context.managerConfig.namespace = 'pipeline';
method = useSecondary ? 'runBrowserPlugin' : 'runServerPlugin';
this.client[method](pluginId, context, err => {
if (err) {
return Materialize.toast(`${name} failed!`, 4000);
}
Materialize.toast(`${name} executed successfully!`, 2000);
});
};
return ForgeActionButton;
});
@@ -1,10 +1,13 @@
{
"GenerateArchitecture": {
"icon": "description",
"hotkey": "shift enter",
"priority": -1
},
"ExecutePipeline": {
"icon": "play_arrow",
"hotkey": "shift enter",
"color": "green",
"priority": 1
},
"ImportTorch": {
@@ -0,0 +1,136 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'blob/BlobClient',
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames'
], function (
BlobClient,
CONSTANTS,
GMEConcepts,
nodePropertyNames
) {
'use strict';
var ImageViewerControl;
ImageViewerControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
// Initialize core collections and variables
this._widget = options.widget;
this.blobClient = new BlobClient({
logger: this._logger.fork('BlobClient')
});
this._currentNodeId = null;
this._logger.debug('ctor finished');
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
// One major concept here is with managing the territory. The territory
// defines the parts of the project that the visualizer is interested in
// (this allows the browser to then only load those relevant parts).
ImageViewerControl.prototype.selectedObjectChanged = function (nodeId) {
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
if (this._currentNodeId) {
this._client.removeUI(this._territoryId);
}
this._currentNodeId = nodeId;
if (typeof this._currentNodeId === 'string') {
// Put new node's info into territory rules
this._selfPatterns = {};
this._selfPatterns[nodeId] = {children: 0}; // Territory "rule"
this._territoryId = this._client.addUI(this, this._eventCallback.bind(this));
this._client.updateTerritory(this._territoryId, this._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
ImageViewerControl.prototype._getObjectDescriptor = function (nodeId) {
var nodeObj = this._client.getNode(nodeId),
objDescriptor,
hash;
if (nodeObj) {
objDescriptor = {
id: undefined,
name: undefined
};
objDescriptor.id = nodeObj.getId();
objDescriptor.name = nodeObj.getAttribute(nodePropertyNames.Attributes.name);
// Get the blob url
hash = nodeObj.getAttribute('data');
if (hash) {
objDescriptor.src = this.blobClient.getDownloadURL(hash);
}
}
return objDescriptor;
};
/* * * * * * * * Node Event Handling * * * * * * * */
ImageViewerControl.prototype._eventCallback = function (events) {
var i = events ? events.length : 0,
event;
this._logger.debug('_eventCallback \'' + i + '\' items');
while (i--) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
this._onLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
break;
}
}
this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
};
ImageViewerControl.prototype._onUpdate =
ImageViewerControl.prototype._onLoad = function (gmeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.updateImage(description.src);
};
ImageViewerControl.prototype._onUnload = function (gmeId) {
this._widget.removeImage(gmeId);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ImageViewerControl.prototype.onActivate = function () {
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
ImageViewerControl.prototype.destroy =
ImageViewerControl.prototype.onDeactivate = function () {
};
return ImageViewerControl;
});
@@ -0,0 +1,99 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Sat Jul 30 2016 07:12:17 GMT-0500 (CDT).
*/
define(['js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/ImageViewer/ImageViewerWidget',
'./ImageViewerControl'
], function (PanelBaseWithHeader,
IActivePanel,
ImageViewerWidget,
ImageViewerControl) {
'use strict';
var ImageViewerPanel;
ImageViewerPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ImageViewerPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ImageViewerPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(ImageViewerPanel.prototype, IActivePanel.prototype);
ImageViewerPanel.prototype._initialize = function () {
var self = this;
//set Widget title
this.setTitle('');
this.widget = new ImageViewerWidget(this.logger, this.$el);
this.widget.setTitle = function (title) {
self.setTitle(title);
};
this.control = new ImageViewerControl({
logger: this.logger,
client: this._client,
widget: this.widget
});
this.onActivate();
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ImageViewerPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
ImageViewerPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ImageViewerPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
ImageViewerPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
ImageViewerPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return ImageViewerPanel;
});
@@ -68,6 +68,9 @@ define([
// The OperationCodeEditor should receive the
if (!this.readOnly) {
// Pass a reference to the panel
this._panels[0].control.currentJobId = nodeId;
// Get the operation base node id and pass it to OpCodeEditor selObjChanged
if (this._territoryId) {
this._client.removeUI(this._territoryId);
@@ -2,9 +2,15 @@
/*jshint browser: true*/
define([
'panels/TextEditor/TextEditorControl'
'panels/TextEditor/TextEditorControl',
'deepforge/LayerParser',
'deepforge/utils',
'deepforge/Constants'
], function (
TextEditorControl
TextEditorControl,
LayerParser,
utils,
Constants
) {
'use strict';
@@ -50,62 +56,120 @@ define([
};
LayerEditorControl.prototype.saveTextFor = function (id, text) {
var r = /:__init\((.*)\)/,
match = text.match(r),
textMatch = match && match[1],
node = this._client.getNode(id),
var node = this._client.getNode(id),
currentAttrs = node.getValidAttributeNames(),
attributes = [],
msg = `Updating layer definition for ${node.getAttribute('name')}`;
types,
ctorAttrs = [],
setterNames,
schema,
currentPtrs = {base: true},
type,
ptr,
msg = `Updating layer definition for ${node.getAttribute('name')}`,
i;
// Parse the attributes and update the node!
if (textMatch) {
attributes = textMatch.split(',')
.map(arg => arg.replace(/\s+/g, '')) // trim white space
.filter(arg => !!arg); // no empty strings!
// Parse the ctorAttrs and update the node!
var layerSchema = LayerParser.parse(text);
if (!layerSchema) {
return TextEditorControl.prototype.saveTextFor.call(this, id, text);
}
if (layerSchema.params) {
ctorAttrs = layerSchema.params;
} else { // inheriting __init
attributes = this.getInheritedAttrs(text);
ctorAttrs = this.getInheritedAttrs(layerSchema);
}
this._client.startTransaction(msg);
TextEditorControl.prototype.saveTextFor.call(this, id, text);
this._client.setAttributes(id, 'name', layerSchema.name);
this._logger.debug(`Setting ctor args to ${ctorAttrs.join(',')}`);
this._client.setAttributes(id, Constants.CTOR_ARGS_ATTR, ctorAttrs.join(','));
types = layerSchema.types || {};
schema = this.getPointerMeta();
// Handle pointer types
for (i = ctorAttrs.length; i--;) {
type = types[ctorAttrs[i]];
if (type && type.substring(0, 3) === 'nn.') {
ptr = ctorAttrs.splice(i, 1)[0];
this._client.setPointerMeta(id, ptr, schema);
currentPtrs[ptr] = true;
}
}
// Remove old pointers
node.getPointerNames().filter(ptr => !currentPtrs[ptr])
.forEach(ptr => this._client.deleteMetaPointer(id, ptr));
// Remove old attributes
_.difference(currentAttrs, attributes)
setterNames = Object.keys(layerSchema.setters);
_.difference(currentAttrs, ctorAttrs, setterNames)
.forEach(attr => this._client.removeAttributeSchema(id, attr));
attributes.forEach((attr, i) =>
this._client.setAttributeSchema(id, attr, {type: 'string', argindex: i}));
// Add setters
for (i = setterNames.length; i--;) {
schema = utils.getSetterSchema(setterNames[i], layerSchema.setters, layerSchema.defaults);
// Get setter attr schema
if (schema.hasOwnProperty('default')) {
this._client.setAttributes(id, setterNames[i], schema.default);
delete schema.default;
}
if (types[setterNames[i]]) {
schema.type = types[setterNames[i]];
}
this._client.setAttributeSchema(id, setterNames[i], schema);
}
ctorAttrs.forEach(attr =>
this._client.setAttributeSchema(id, attr, {
type: types[attr] || 'string'
})
);
this._client.completeTransaction();
};
LayerEditorControl.prototype.getInheritedAttrs = function (code) {
LayerEditorControl.prototype.getPointerMeta = function () {
var archNode = this._client.getAllMetaNodes()
.find(node => node.getAttribute('name') === 'Architecture');
if (!archNode) {
throw 'Could not find the "Architecture" node!';
}
return {
min: 1,
max: 1,
items: [
{
id: archNode.getId(),
max: 1
}
]
};
};
LayerEditorControl.prototype.getInheritedAttrs = function (layerSchema) {
// Get the base class
var r = /torch.class\((.*)\)/,
match = code.match(r),
baseType,
metanode,
textMatch = match && match[1];
var metanode;
if (textMatch) {
baseType = textMatch.split(',')[1]
.replace(/^\s*['"]nn\./, '')
.replace(/['"]\s*$/, '');
this._logger.debug(`inheriting the attributes from ${baseType}`);
if (layerSchema.baseType) {
this._logger.debug(`inheriting the attributes from ${layerSchema.baseType}`);
// Get the meta node and valid attribute names
metanode = this._client.getAllMetaNodes()
.find(node => node.getAttribute('name') === baseType);
.find(node => node.getAttribute('name') === layerSchema.baseType);
if (metanode) {
return metanode.getValidAttributeNames()
.filter(attr => attr !== 'name');
} else {
// Check if the type is known by torch
this._logger.warn(`Unknown base type ${baseType}. Assuming attributes are []`);
this._logger.warn(`Unknown base type ${layerSchema.baseType}. Assuming attributes are []`);
}
}
return [];
@@ -83,17 +83,20 @@ define([
// Check if it is a line
if (desc.id !== this._currentNodeId) {
var points = (node.getAttribute('points') || '').split(';')
.map(pair => {
var nums = pair.split(','),
x = +nums[0],
y = +nums[1];
var rawPoints = node.getAttribute('points') || '',
points = rawPoints.split(';')
.filter(data => !!data) // remove any ''
.map(pair => {
var nums = pair.split(','),
x = parseFloat(nums[0]),
y = parseFloat(nums[1]);
return {
x: x,
y:y
};
});
return {
x: x,
y:y
};
});
desc.type = 'line';
desc.points = points;
}
@@ -65,6 +65,8 @@ define([
return null;
}
};
this._widget.toggleEmbeddedPanel = () => this.toggleEmbeddedPanel();
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
@@ -92,9 +94,11 @@ define([
// Update the territory
this.territory[type] = {};
this.territory[type][DeepForge.places[dirname]] = {children: 1};
this.ui[type] = this._client.addUI(this, this.handleEvents.bind(this, type));
this._client.updateTerritory(this.ui[type], this.territory[type]);
DeepForge.places[dirname]().then(id => {
this.territory[type][id] = {children: 1};
this.ui[type] = this._client.addUI(this, this.handleEvents.bind(this, type));
this._client.updateTerritory(this.ui[type], this.territory[type]);
});
});
}
};
+49 -10
Ver Arquivo
@@ -9,6 +9,7 @@ define([
'widgets/MainView/MainViewWidget',
'./MainViewControl',
'panels/PipelineIndex/PipelineIndexPanel',
'panels/ExecutionIndex/ExecutionIndexPanel',
'deepforge/globals'
], function (
PanelBaseWithHeader,
@@ -16,6 +17,7 @@ define([
MainViewWidget,
MainViewControl,
PipelineIndexPanel,
ExecutionIndexPanel,
DeepForge
) {
'use strict';
@@ -38,12 +40,14 @@ define([
this.$nav = $('<div>', {id: 'nav-container'});
this.$el.css({padding: 0});
this.embeddedPanel = new PipelineIndexPanel(layoutManager, params);
this.$embedded = this.embeddedPanel.$el;
this.$embedded.addClass('embedded');
this.$el.append(this.$nav, this.$embedded);
this.embeddedPanels = [
PipelineIndexPanel,
ExecutionIndexPanel
];
this.nextPanelIndex = 0;
this._lm = layoutManager;
this._params = params;
this.$el.append(this.$nav);
this._initialize();
this.logger.debug('ctor finished');
@@ -66,15 +70,48 @@ define([
widget: this.widget
});
var controlObjectChanged = this.control.selectedObjectChanged;
this.control.selectedObjectChanged = nodeId => {
this.embeddedPanel.control.selectedObjectChanged(DeepForge.places.MyPipelines);
return controlObjectChanged.call(this.control, nodeId);
this.control.toggleEmbeddedPanel = this.toggleEmbeddedPanel.bind(this);
var selectedObjectChanged = this.control.selectedObjectChanged;
this.control.selectedObjectChanged = id => {
this.getEmbeddedNode().then(nodeId =>
this.embeddedPanel.control.selectedObjectChanged(nodeId));
selectedObjectChanged.call(this.control, id);
};
this.toggleEmbeddedPanel(true);
this.onActivate();
};
MainViewPanel.prototype.getEmbeddedNode = function() {
if (this.nextPanelIndex === 1) {
return DeepForge.places.MyPipelines();
} else {
return DeepForge.places.MyExecutions();
}
};
MainViewPanel.prototype.toggleEmbeddedPanel = function (silent) {
var Panel = this.embeddedPanels[this.nextPanelIndex];
this.nextPanelIndex = (this.nextPanelIndex + 1) % this.embeddedPanels.length;
if (this.embeddedPanel) { // Remove current
this.embeddedPanel.destroy();
this.$embedded.remove();
}
this.embeddedPanel = new Panel(this._lm, this._params);
this.$embedded = this.embeddedPanel.$el;
this.$embedded.addClass('main-view-embedded');
this.$el.append(this.$embedded);
// Call on Resize and selectedObjectChanged
this.onResize(this.width, this.height);
if (!silent) {
this.getEmbeddedNode().then(nodeId =>
this.embeddedPanel.control.selectedObjectChanged(nodeId));
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
MainViewPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
@@ -98,6 +135,8 @@ define([
margin: 'inherit'
});
this.embeddedPanel.onResize(embeddedWidth, height);
this.width = width;
this.height = height;
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
@@ -4,11 +4,13 @@
define([
'panels/TextEditor/TextEditorControl',
'deepforge/viz/OperationControl',
'deepforge/viz/Execute',
'deepforge/Constants',
'underscore'
], function (
TextEditorControl,
OperationControl,
Execute,
CONSTANTS,
_
) {
@@ -20,15 +22,23 @@ define([
OperationCodeEditorControl = function (options) {
options.attributeName = 'code';
TextEditorControl.call(this, options);
Execute.call(this, this._client, this._logger);
this.currentJobId = null;
};
_.extend(
OperationCodeEditorControl.prototype,
OperationControl.prototype,
TextEditorControl.prototype
TextEditorControl.prototype,
Execute.prototype
);
// Override ObjectDescriptor
OperationCodeEditorControl.prototype._initWidgetEventHandlers = function () {
TextEditorControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getOperationAttributes = this.getOperationAttributes.bind(this);
this._widget.executeOrStopJob = this.executeOrStopJob.bind(this);
};
OperationCodeEditorControl.prototype.TERRITORY_RULE = {children: 3};
OperationCodeEditorControl.prototype._getObjectDescriptor = function (id) {
var desc = TextEditorControl.prototype._getObjectDescriptor.call(this, id),
@@ -58,6 +68,35 @@ define([
}
};
OperationCodeEditorControl.prototype.getOperationAttributes = function () {
var node = this._client.getNode(this._currentNodeId),
attrs = node.getValidAttributeNames(),
rmAttrs = ['name', 'code', CONSTANTS.LINE_OFFSET],
i;
for (var j = rmAttrs.length; j--;) {
i = attrs.indexOf(rmAttrs[j]);
if (i > -1) {
attrs.splice(i, 1);
}
}
return attrs;
};
OperationCodeEditorControl.prototype.executeOrStopJob = function () {
var job;
if (this.currentJobId) { // Only if nested in a job
job = this._client.getNode(this.currentJobId);
if (this.isRunning(job)) {
this.stopJob(job);
} else {
this.executeJob(job);
}
}
};
// Line offset handling
OperationCodeEditorControl.prototype.offsetNodeChanged = function (id) {
// Create a territory for this node
@@ -9,6 +9,7 @@ define([
this._widget.allDataTypeIds = this.allDataTypeIds.bind(this);
this._widget.allValidReferences = this.allValidReferences.bind(this);
this._widget.addRefTo = this.addRefTo.bind(this);
this._widget.setRefType = this.setRefType.bind(this);
this._widget.changePtrName = this.changePtrName.bind(this);
this._widget.removePtr = this.removePtr.bind(this);
this._widget.getCreationNode = this.getCreationNode.bind(this);
@@ -138,6 +139,29 @@ define([
this._client.completeTransaction();
};
OperationInterfaceEditorEvents.prototype.setRefType = function(ref, targetId) {
var meta = this._client.getPointerMeta(this._currentNodeId, ref),
msg = `Setting ${ref} reference type to ${targetId}`;
if (!meta) {
this.logger.debug(`No meta found for ${ref}. Creating a new reference to ${targetId}`);
meta = {
min: 1,
max: 1,
items: []
};
}
meta.items.push({
id: targetId,
max: 1
});
this._client.startTransaction(msg);
this._client.setPointerMeta(this._currentNodeId, ref, meta);
this._client.completeTransaction();
};
OperationInterfaceEditorEvents.prototype.changePtrName = function(from, to) {
var opNode = this._client.getNode(this._currentNodeId),
name = opNode.getAttribute('name'),
@@ -255,13 +255,23 @@ define([
};
OperationInterfaceEditorControl.prototype.getPtrDescriptor = function(name) {
var targetId = this._client.getPointerMeta(this._currentNodeId, name)
.items[0].id,
target = this._client.getNode(targetId),
decManager = this._client.decoratorManager,
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
var Decorator = this._client.decoratorManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
id = 'ptr_'+name,
used = this.isUsedInput(name);
used = this.isUsedInput(name),
ptrMeta = this._client.getPointerMeta(this._currentNodeId, name),
targetId,
target,
baseName;
if (!ptrMeta || ptrMeta.items.length === 0) {
// No known type
this._logger.error(`No known target type for "${name}" reference`);
baseName = null;
} else {
targetId = ptrMeta.items[0].id;
target = this._client.getNode(targetId);
baseName = target.getAttribute('name');
}
if (used === null) {
used = this._usage[id] !== undefined ? this._usage[id] : true;
@@ -270,7 +280,8 @@ define([
return {
id: id,
isPointer: true,
baseName: target.getAttribute('name'),
baseName: baseName,
isUnknown: !baseName,
Decorator: Decorator,
used: used,
attributes: {},
@@ -5,6 +5,7 @@
// metadata, provides a pagination bar in the lower left to page through
// the metadata results
define([
'text!./icons.json',
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'panels/LogViewer/LogViewerPanel',
@@ -13,6 +14,7 @@ define([
'text!api/visualizers',
'css!./OutputViewer.css'
], function (
IconTxt,
PanelBaseWithHeader,
IActivePanel,
LogViewer,
@@ -23,7 +25,8 @@ define([
'use strict';
var OutputViewerPanel,
Visualizers = JSON.parse(VisualizersJSON);
Visualizers = JSON.parse(VisualizersJSON),
IconFor = JSON.parse(IconTxt);
OutputViewerPanel = function (layoutManager, params) {
var options = {};
@@ -64,7 +67,7 @@ define([
this.$pagerList = $('<ul>', {class: 'pagination'});
// Add the console item
var logviewer = $('<li class="active"><a>Console</a></li>');
var logviewer = $('<li class="active"><a><span class="glyphicon glyphicon-console"></span> Console</a></li>');
this.$logviewer = logviewer.find('a');
this.$selected = this.$logviewer;
this.$pagerList.append(logviewer);
@@ -89,13 +92,18 @@ define([
OutputViewerPanel.prototype.selectOutput = function (element) {
if (this.$selected !== element) {
// Update the panel
var dataId = element.data('id');
while (element.prop('tagName').toLowerCase() !== 'a' && element.length) {
element = element.parent();
}
dataId = element.data('id');
this.$selected.parent().removeClass('active');
element.parent().addClass('active');
this.$selected = element;
// Update the panel
var dataId = element.data('id');
if (dataId) {
this.loadOutputFor(dataId);
} else { // Set the logviewer
@@ -218,10 +226,8 @@ define([
};
OutputViewerPanel.prototype.onUpdate = function (nodeId) {
var name = this._client.getNode(nodeId).getAttribute('name');
if (this._pages[nodeId]) {
this._pages[nodeId].find('a').text(name);
this.updatePage(nodeId);
}
};
@@ -249,14 +255,29 @@ define([
}
};
OutputViewerPanel.prototype.updatePage = function (nodeId) {
var node = this._client.getNode(nodeId),
baseId = node.getBaseId(),
base = this._client.getNode(baseId),
type = base.getAttribute('name'),
name = node.getAttribute('name'),
icon = IconFor[type] || 'info-sign',
anchor = this._pages[nodeId].find('a'),
span = document.createElement('span');
span.className = 'glyphicon glyphicon-' + icon;
anchor.empty();
anchor.html(span.outerHTML + ' ' + name);
};
OutputViewerPanel.prototype.addToPager = function (name, nodeId) {
var $el = $('<li>'),
$a = $('<a>');
$a.text(name);
$a.attr('data-id', nodeId);
$el.append($a);
this._pages[nodeId] = $el;
this.updatePage(nodeId);
this.$pager.removeClass('empty');
this.$pagerList.append($el);
@@ -284,6 +305,7 @@ define([
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
OutputViewerPanel.prototype.destroy = function () {
this.activePanel.destroy();
this.clearTerritory();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
@@ -0,0 +1,5 @@
{
"Image": "picture",
"Console": "console",
"Graph": "random"
}
@@ -62,7 +62,7 @@ define(['js/PanelBase/PanelBaseWithHeader',
});
// Editable pipeline name
this.$panelHeaderTitle.on('dblclick', () => this.editTitle());
this.$panelHeaderTitle.on('click', () => this.editTitle());
this.onActivate();
};
@@ -5,6 +5,7 @@ define([
'deepforge/globals',
'widgets/EasyDAG/EasyDAGWidget',
'widgets/EasyDAG/AddNodeDialog',
'./SelectionManager',
'./Layer',
'q',
'underscore',
@@ -13,6 +14,7 @@ define([
DeepForge,
EasyDAGWidget,
AddNodeDialog,
SelectionManager,
Layer,
Q,
_
@@ -31,6 +33,7 @@ define([
_.extend(ArchEditorWidget.prototype, EasyDAGWidget.prototype);
ArchEditorWidget.prototype.ItemClass = Layer;
ArchEditorWidget.prototype.SelectionManager = SelectionManager;
ArchEditorWidget.prototype.onCreateInitialNode = function() {
var nodes = this.getValidInitialNodes();
@@ -0,0 +1,52 @@
/* globals _, WebGMEGlobal, define*/
define([
'widgets/EasyDAG/SelectionManager',
'deepforge/viz/Buttons'
], function(
ManagerBase,
Buttons
) {
var client = WebGMEGlobal.Client;
var SelectionManager = function() {
ManagerBase.apply(this, arguments);
};
_.extend(SelectionManager.prototype, ManagerBase.prototype);
SelectionManager.prototype.createActionButtons = function(width, height) {
var disabled,
btn;
ManagerBase.prototype.createActionButtons.call(this, width, height);
if (!this.selectedItem.isConnection) {
disabled = !this._isCustomLayer();
// Check that the base type
btn = new Buttons.GoToBase({
$pEl: this.$selection,
context: this._widget,
item: this.selectedItem,
disabled: disabled,
x: width,
y: 0
});
}
return btn;
};
SelectionManager.prototype._isCustomLayer = function() {
var node = client.getNode(this.selectedItem.id),
attrNames;
if (node) {
attrNames = node.getAttributeNames();
return attrNames.indexOf('code') !== -1;
}
return false;
};
return SelectionManager;
});
@@ -0,0 +1,13 @@
<table class="table">
<thead>
<tr>
<td></td>
<td>Name</td>
<td>Creation Date</td>
<td>Origin Pipeline</td>
<td>Duration</td>
</tr>
</thead>
<tbody class="execs-content">
</tbody>
</table>
@@ -0,0 +1,325 @@
/*globals define, WebGMEGlobal, $*/
/*jshint browser: true*/
define([
'deepforge/viz/Utils',
'widgets/LineGraph/LineGraphWidget',
'text!./ExecTable.html',
'css!./styles/ExecutionIndexWidget.css'
], function (
Utils,
LineGraphWidget,
TableHtml
) {
'use strict';
var ExecutionIndexWidget,
WIDGET_CLASS = 'execution-index';
ExecutionIndexWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this.nodes = {};
this.graphs = {};
this.checkedIds = [];
this._initialize();
this._logger.debug('ctor finished');
};
ExecutionIndexWidget.prototype._initialize = function () {
// set widget class
this.$el.addClass(WIDGET_CLASS);
// Create split screen
this.$left = $('<div>', {class: 'left'});
this.$right = $('<div>', {class: 'right'});
this.$el.append(this.$left, this.$right);
// Create the table
this.$table = $(TableHtml);
this.$table.on('click', '.exec-row', event => this.onExecutionClicked(event));
this.$table.on('click', '.node-nav', event => this.navToNode(event));
this.$left.append(this.$table);
this.$execList = this.$table.find('.execs-content');
// Create the graph in the right half
this.lineGraph = new LineGraphWidget(this._logger, this.$right);
this.defaultSelection = null;
this.hasRunning = false;
};
ExecutionIndexWidget.prototype.navToNode = function (event) {
var id = event.target.getAttribute('data-id');
if (typeof id === 'string') {
WebGMEGlobal.State.registerActiveObject(id);
event.stopPropagation();
}
this._logger.warn('No node id found for node-nav!');
};
ExecutionIndexWidget.prototype.onExecutionClicked = function (event) {
var target = event.target,
checked,
id;
while (!target.getAttribute('data-id')) {
if (!target.parentNode) {
this._logger.error('could not find execution id for ' + event);
return;
}
target = target.parentNode;
}
id = target.getAttribute('data-id');
checked = this.nodes[id].$checkbox.checked;
if (event.target.tagName.toLowerCase() !== 'input') {
this.setSelect(id, !checked);
} else {
this.setExecutionDisplayed(id, checked);
}
};
ExecutionIndexWidget.prototype.onWidgetContainerResize = function (width, height) {
this.$left.css({
width: width/2,
height: height
});
this.$right.css({
left: width/2,
width: width/2,
height: height
});
this.lineGraph.onWidgetContainerResize(width/2, height);
this._logger.debug('Widget is resizing...');
};
// Adding/Removing/Updating items
ExecutionIndexWidget.prototype.addNode = function (desc) {
var isFirstNode = Object.keys(this.nodes).length === 0;
if (desc.type === 'Execution') {
// Add node to a table of nodes
this.addExecLine(desc);
this.updateSelected(desc);
} else if (desc.type === 'line') {
desc.type = 'line';
this.lineGraph.addNode(desc);
}
if (isFirstNode) {
this.updateTimes();
}
};
ExecutionIndexWidget.prototype.updatePipelineName = function (execId, name) {
if (this.nodes[execId]) {
this.nodes[execId].$pipeline.text(name);
}
};
ExecutionIndexWidget.prototype.addExecLine = function (desc) {
var row = $('<tr>', {class: 'exec-row', 'data-id': desc.id}),
checkBox = $('<input>', {type: 'checkbox'}),
statusClass = Utils.ClassForJobStatus[desc.status],
fields,
pipeline,
name,
duration = $('<div>'),
td;
pipeline = $('<a>', {
class: 'node-nav',
'data-id': desc.originId
}).text(desc.pipelineName || 'view pipeline');
name = $('<a>', {class: 'node-nav', 'data-id': desc.id})
.text(desc.name);
fields = [
checkBox,
name,
Utils.getDisplayTime(desc.originTime),
pipeline,
duration
];
for (var i = 0; i < fields.length; i++) {
td = $('<td>');
if ((typeof fields[i]) === 'string') {
td.text(fields[i]);
} else {
td.append(fields[i]);
}
row.append(td);
}
this._logger.debug(`Adding execution ${desc.name} (${desc.id}) to list`);
this.$execList.append(row);
row.addClass(statusClass);
this.nodes[desc.id] = {
statusClass: statusClass,
desc: desc,
$el: row,
$checkbox: checkBox[0],
$pipeline: pipeline,
$duration: duration,
$name: name
};
this.updateTime(desc.id, true);
};
ExecutionIndexWidget.prototype.getDurationText = function (duration) {
var hours,
min,
sec;
sec = duration/1000;
hours = Math.floor(sec/3600);
sec = sec%3600;
min = Math.floor(sec/60);
sec = Math.floor(sec%60);
return `${hours}:${min}:${sec}`;
};
ExecutionIndexWidget.prototype.updateTime = function (id, force) {
var desc = this.nodes[id].desc,
duration = 'unknown';
if (desc.status === 'running') {
if (desc.startTime) {
duration = this.getDurationText(Date.now() - desc.startTime);
}
this.nodes[id].$duration.text(duration);
return true;
} else if (force) {
if (desc.endTime && desc.startTime) {
duration = this.getDurationText(desc.endTime - desc.startTime);
}
this.nodes[id].$duration.text(duration);
return true;
}
return false;
};
ExecutionIndexWidget.prototype.updateTimes = function () {
var nodeIds = Object.keys(this.nodes),
updated = false;
for (var i = nodeIds.length; i--;) {
updated = this.updateTime(nodeIds[i]) || updated;
}
if (updated) { // if there are still nodes, call again!
setTimeout(this.updateTimes.bind(this), 1000);
}
};
ExecutionIndexWidget.prototype.removeNode = function (id) {
if (this.nodes[id]) {
this.nodes[id].$el.remove();
} else if (this.graphs[id]) {
delete this.graphs[id];
}
delete this.nodes[id];
this.lineGraph.removeNode(id); // 'nop' if node is not line
};
ExecutionIndexWidget.prototype.updateSelected = function (desc) {
// If the running pipeline has been unselected, don't reselect it!
if (desc.status === 'running') {
this.hasRunning = true;
this.setSelect(desc.id, true);
if (this.defaultSelection) {
this.setSelect(this.defaultSelection, false);
}
} else if (!this.hasRunning && !this.defaultSelection) {
this.defaultSelection = desc.id;
this.setSelect(desc.id, true);
}
};
ExecutionIndexWidget.prototype.toggleAbbreviations = function (show, ids) {
var node,
desc,
name;
ids = ids || this.checkedIds;
for (var i = ids.length; i--;) {
node = this.nodes[ids[i]];
desc = node.desc;
name = show ? `${desc.name} (${desc.abbr})` : desc.name;
node.$name.text(name);
}
};
ExecutionIndexWidget.prototype.setSelect = function (id, checked) {
var wasChecked = this.checkedIds.length > 1,
isChecked;
this.nodes[id].$checkbox.checked = checked;
// If multiple are checked, display the abbreviation
if (checked) {
this.checkedIds.push(id);
} else {
var k = this.checkedIds.indexOf(id);
if (k !== -1) {
this.checkedIds.splice(k, 1);
}
}
isChecked = this.checkedIds.length > 1;
if (isChecked !== wasChecked) {
this.toggleAbbreviations(isChecked);
}
// Update the given node
if (!checked || isChecked) {
this.toggleAbbreviations(checked, [id]);
}
this.setExecutionDisplayed(id, checked);
};
ExecutionIndexWidget.prototype.updateNode = function (desc) {
var node = this.nodes[desc.id];
if (node) {
node.$name.text(desc.name);
node.$el.removeClass(node.statusClass);
node.$el.addClass(Utils.ClassForJobStatus[desc.status]);
if (Utils.ClassForJobStatus[desc.status] !== node.statusClass) {
// Only update the selection if the status has changed.
// ie, it has started running
this.updateSelected(desc);
}
this._logger.debug(`setting execution ${desc.id} to ${desc.status}`);
node.statusClass = Utils.ClassForJobStatus[desc.status];
node.desc = desc;
} else if (desc.type === 'line') {
this.lineGraph.updateNode(desc);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ExecutionIndexWidget.prototype.destroy = function () {
};
ExecutionIndexWidget.prototype.onActivate = function () {
this._logger.debug('ExecutionIndexWidget has been activated');
};
ExecutionIndexWidget.prototype.onDeactivate = function () {
this._logger.debug('ExecutionIndexWidget has been deactivated');
};
return ExecutionIndexWidget;
});
@@ -0,0 +1,21 @@
/**
* This file is for any css that you may want for this visualizer.
*
* Ideally, you would use the scss file also provided in this directory
* and then generate this file automatically from that. However, you can
* simply write css if you prefer
*/
.execution-index.panel-body {
padding: 0;
}
.execution-index .left {
position: absolute;
background-color: #eee;
}
.execution-index .right {
position: absolute;
background-color: #eee;
}
@@ -0,0 +1,7 @@
/**
* This file is for any scss that you may want for this visualizer.
*/
.execution-index {
outline: none;
}
@@ -48,8 +48,8 @@ define([
var title = nodeName === undefined ? this._currentTitle : nodeName;
this._currentTitle = title;
if (this.isSnapshot) {
title += ' (SNAPSHOT)';
if (!this.isSnapshot) {
title += ' (DEBUG)';
}
this._setTitle(title);
@@ -0,0 +1,107 @@
/*globals define, $*/
/*jshint browser: true*/
define([
'css!./styles/ImageViewerWidget.css'
], function (
) {
'use strict';
var ImageViewerWidget,
NO_IMAGE_URL = 'extlib/src/visualizers/widgets/ImageViewer/no-image.gif',
WIDGET_CLASS = 'image-viewer';
ImageViewerWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this._initialize();
this._logger.debug('ctor finished');
};
ImageViewerWidget.prototype._initialize = function () {
// set widget class
this.$el.addClass(WIDGET_CLASS);
this.zoom = 1;
this.left = 0;
this.top = 0;
this.width = 0;
this.height = 0;
this.img = {
width: 0,
height: 0
};
this.$image = $('<img>');
this.$el.append(this.$image);
this.$image.on('load', () => {
this.img.width = this.$image.width();
this.img.height = this.$image.height();
this.centerImage();
});
this.updateImage(NO_IMAGE_URL);
// Zoom functionality
this.$el[0].onwheel = event => {
if (event.ctrlKey || event.metaKey || event.altKey) {
var dz = -event.deltaY/20;
this.zoom += dz;
this.centerImage();
event.stopPropagation();
event.preventDefault();
}
};
};
ImageViewerWidget.prototype.centerImage = function () {
var left,
top;
this.left = this.width/2 - (this.img.width*this.zoom/2);
this.top = this.height/2 - (this.img.height*this.zoom/2);
left = this.left/this.zoom;
top = this.top/this.zoom;
this.$image.css({
left: left,
top: top,
zoom: this.zoom
});
};
ImageViewerWidget.prototype.onWidgetContainerResize = function (width, height) {
this.$el.css({
width: width,
height: height
});
this.width = width;
this.height = height;
this.centerImage();
};
ImageViewerWidget.prototype.updateImage = function (url) {
url = url || NO_IMAGE_URL;
this.zoom = 1;
this.$image.attr('src', url);
};
ImageViewerWidget.prototype.removeImage = function () {
// Change to 'no picture' image
this.updateImage(NO_IMAGE_URL);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
ImageViewerWidget.prototype.destroy = function () {
};
ImageViewerWidget.prototype.onActivate = function () {
this._logger.debug('ImageViewerWidget has been activated');
};
ImageViewerWidget.prototype.onDeactivate = function () {
this._logger.debug('ImageViewerWidget has been deactivated');
};
return ImageViewerWidget;
});
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 3.7 KiB

@@ -0,0 +1,5 @@
.image-viewer img {
position: absolute;
image-rendering: pixelated;
}
@@ -1,4 +1,4 @@
/*globals define, d3, nv */
/*globals define, d3, nv, _ */
/*jshint browser: true*/
define([
@@ -16,7 +16,7 @@ define([
this.$el = container;
this.lineData = [];
this.lineData = {};
this._initialize();
this._logger.debug('ctor finished');
@@ -35,7 +35,6 @@ define([
this.$chart = d3.select(this.$el[0]).append('svg');
nv.addGraph(() => {
var chart = nv.models.lineChart()
//.margin({left: 100})
.useInteractiveGuideline(true)
.showLegend(true)
.showYAxis(true)
@@ -49,6 +48,7 @@ define([
.axisLabel(this.options.xAxis);
}
chart.yAxis.tickFormat(d3.format('.02f'));
if (this.options.yAxis) {
chart.yAxis
.axisLabel(this.options.yAxis);
@@ -69,7 +69,9 @@ define([
};
LineGraphWidget.prototype.getData = function () {
return Object.keys(this.lineData).map(id => this.lineData[id]);
return Object.keys(this.lineData)
.map(id => this.lineData[id])
.filter(data => data.values.length !== 0); // hide empty lines
};
// Adding/Removing/Updating items
@@ -82,20 +84,20 @@ define([
values: desc.points
};
}
this.updateChartData();
this.refreshChart();
}
};
LineGraphWidget.prototype.removeNode = function (id) {
delete this.lineData[id];
this.updateChartData();
this.refreshChart();
};
LineGraphWidget.prototype.updateNode = function (desc) {
if (desc && this.lineData[desc.id]) {
this.lineData[desc.id].values = desc.points;
this.lineData[desc.id].key = desc.name;
this.updateChartData();
this.refreshChart();
}
};
@@ -115,6 +117,9 @@ define([
}
};
LineGraphWidget.prototype.refreshChart =
_.debounce(LineGraphWidget.prototype.updateChartData, 50);
LineGraphWidget.prototype.updateChart = function () {
if (this.chart) {
this.chart.update();
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -1 +0,0 @@
{"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"AAqBA,oBAfA,oBAgBI,KAAM,KAmXN,gBAAiB,WAhFrB,kBA+DA,uBAnWA,oBAfA,oBAmYI,gBAAiB,WAmErB,UAAW,UAJX,mBAvcA,eAsbA,uBA8BA,uCACI,eAAgB,KA+DpB,WA7QA,aAoRI,QAAS,MAST,sBAAuB,KAEvB,mBAAoB,KAtiBxB,eAEI,QAAS,EAuCb,2BA4JA,0DACI,QAAS,EAjMb,oBAEI,OAAQ,KACR,eAAgB,IAIpB,2BACI,eAAgB,IAGpB,gCACI,eAAgB,EAGpB,oBAEI,OAAQ,QAIZ,0BACI,0BACA,eAAgB,IAGpB,mCACI,YAAa,IAGjB,sCACA,uCACA,uCACI,YAAa,OAOjB,oBACI,aAAc,IAEd,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAG3C,0BACI,aAAc,EAGlB,2BACI,KAAM,QAGV,oBACI,KAAM,YAGV,2BACI,KAAM,cAKV,sCAFA,mCACA,6CAEI,eAAgB,EAEhB,WAAY,aAAa,MAAM,OAC/B,gBAAiB,aAAa,MAAM,OACpC,mBAAoB,aAAa,MAAM,OAK3C,8CACA,4CAHA,yCACA,mDAGI,aAAc,EAGlB,sCACA,6CACI,YAAa,IACb,KAAM,cACN,OAAQ,YAIZ,yBACE,aAAc,GAGhB,+BAIA,6BAHE,aAAc,EAOhB,6BACE,OAAQ,KAGV,uBACE,aAAc,MAGhB,gBAAkB,KAAM,KAAK,WAC7B,4BAA8B,aAAc,GAC5C,kCAAoC,aAAc,EAClD,2BAA6B,OAAQ,KAAM,aAAc,IACzD,mCAAqC,OAAQ,KAAM,KAAM,KAAM,aAAc,MAC7E,+BAAiC,OAAQ,KAAM,aAAc,MAC7D,8BAAgC,OAAQ,KAAM,aAAc,KAC5D,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,gCAAkC,KAAM,KACxC,0BAA4B,UAAW,KAAM,YAAa,IAC1D,6BAA+B,KAAM,KAGrC,0BACI,KAAM,QACN,aAAc,GAElB,gCACI,aAAc,GAGlB,2CACI,aAAc,IAGlB,iDACI,aAAc,IAGlB,yDACI,OAAQ,QACR,KAAM,QAGV,yDACI,OAAQ,QACR,KAAM,QAGV,wDACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAIxE,uCACI,OAAQ,KAIZ,eACE,OAAQ,KACR,aAAc,MAEhB,eACE,OAAQ,KACR,eAAgB,GAElB,oBACE,aAAc,EAOhB,4BACI,aAAa,EACb,aAAa,EAGjB,8BACI,aAAa,EACb,aAAa,EAGjB,qDACI,aAAa,EACb,eAAe,EAQnB,kCACI,aAAc,IAGlB,wCACI,aAAc,EAElB,8BACI,KAAM,KAGV,8BACI,OAAQ,KAGZ,oDACI,aAAc,EACd,eAAgB,EAGpB,sDACI,aAAc,aACd,eAAgB,aAIpB,6CACI,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAKxE,iCADA,4CAEI,aAAc,IACd,aAAc,cACd,eAAgB,cAIpB,2BACI,OAAQ,KACR,eAAgB,EAChB,KAAM,KACN,aAAc,EAKlB,oBACI,OAAQ,UAUZ,aAEI,oBAAqB,KAErB,gBAAiB,KACjB,iBAAkB,KAClB,YAAa,KAEb,MAAM,KACN,OAAO,KAMX,0BAA2B,2BACvB,gBAAiB,EAAE,IAAI,KAAK,eAC5B,mBAAoB,EAAE,IAAI,KAAK,eAC/B,WAAY,EAAE,IAAI,KAAK,eAEvB,sBAAuB,IACvB,mBAAoB,IACpB,cAAe,IAInB,WACI,KAAM,IAAO,KAAK,MAGtB,aACI,KAAM,IAAK,KAAK,MAGpB,qBACI,KAAM,KACN,aAAc,EAGlB,gBACI,UAAW,KACX,YAAa,IAQjB,kBACI,aAAc,KAIlB,uBACI,KAAM,KACN,OAAQ,KAQZ,4BACI,OAAQ,QAGZ,qCACI,aAAc,EAIlB,wBACI,aAAc,YAGlB,+BACI,OAAQ,KACR,aAAc,GACd,KAAM,KACN,aAAc,GAOlB,aACE,WACE,aAAc,EACd,aAAc,GAIlB,oCACI,aAAc,IAGlB,0CACI,aAAc,IAGlB,6CACI,OAAQ,QAGZ,6CACI,OAAQ,QAIZ,uBACI,KAAM,KACN,OAAQ,KACR,eAAgB,GAIpB,uBACI,KAAM,KACN,eAAgB,GAGpB,4CAEI,KAAM,KACN,aAAc,GACd,OAAQ,KACR,gBAAiB,WAGrB,qCACI,aAAc,EACjB,aAAc,IAIf,8BACE,KAAM,KACN,OAAQ,KACR,aAAc,EACd,eAAgB,EAChB,iBAAkB,EAAG,EAUvB,2BACI,UAAW,KACX,KAAM,qBAGV,4BACI,OAAQ,KACR,aAAc,EAGlB,kBAhBI,WAAY,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OACvF,gBAAiB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5F,mBAAoB,aAAa,MAAM,OAAQ,aAAa,MAAM,OAAQ,eAAe,MAAM,OAe/F,OAAQ,KACR,aAAc,IACd,eAAgB,EAIhB,aAAc,GAElB,yBACI,aAAc,EAKlB,4BACI,aAAc,EACd,eAAgB,EAIpB,iCACI,aAAc,KACd,eAAgB,GAGpB,kCACI,aAAc,EAWlB,wBACI,KAAM,KAOV,2CACI,OAAQ,KACR,aAAc,MAGlB,uBACA,yBACI,eAAgB,IA4LpB,+BAvIA,WAwII,eAAe,KA1LnB,oBACI,aAAc,EACd,eAAgB,EAGpB,kCACA,kCACI,aAAc,EACd,UAAW,KACX,YAAa,IAGjB,kCACI,OAAQ,KAGZ,oCACI,OAAQ,QACR,KAAM,QAGV,oCACI,OAAQ,QACR,KAAM,QAGV,wCACI,YAAa,IACb,UAAW,MAsEf,cAsCA,wBACI,YAAa,IA1GjB,kCACI,aAAc,GACd,eAAgB,EAChB,WAAY,aAAa,MAAM,OAAQ,eAAe,MAAM,OAC5D,gBAAiB,aAAa,MAAM,OAAQ,eAAe,MAAM,OACjE,mBAAoB,aAAa,MAAM,OAAQ,eAAe,MAAM,OAGxE,wCACI,aAAc,GAIlB,0CACI,eAAgB,EAChB,aAAc,EAIlB,WACI,SAAU,SAEV,MAAO,cACP,QAAS,IAET,QAAS,MAGT,YAAa,MACb,UAAW,KACX,WAAY,KAGZ,YAAa,OAGb,oBAAqB,KAErB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAIb,WAAY,qBACZ,OAAQ,IAAI,MAAM,eAClB,cAAe,IAqBnB,cAgBA,aACI,OAAQ,EAER,WAAY,OAlChB,4BAA6B,6BACzB,WAAY,QAAQ,KAAK,OACzB,gBAAiB,QAAQ,KAAK,OAC9B,mBAAoB,QAAQ,KAAK,OAEjC,iBAAkB,MAClB,sBAAuB,MACvB,yBAA0B,MAG9B,uBACA,uBACI,QAAS,IAGb,cAEI,QAAS,IAAI,KACb,YAAa,KAEb,iBAAkB,sBAClB,MAAO,cAGP,cAAe,IAAI,MAAM,QAEzB,sBAAuB,IAAI,IAAI,EAAE,EACjC,mBAAoB,IAAI,IAAI,EAAE,EAC9B,cAAe,IAAI,IAAI,EAAE,EAG7B,aAEI,QAAS,IAAI,KAIjB,gBACI,QAAS,aACT,OAAQ,IAAI,EAGhB,iBACI,OAAQ,IACR,eAAe,EAInB,oBACI,QAAS,IAAI,IAAI,IAAI,EACrB,eAAgB,OAMpB,8BACI,YAAa,IAEjB,0BACI,WAAY,MACZ,YAAa,IAGjB,4BACI,MAAO,QAGX,iCACI,QAAS,IAAI,IAAI,IAAI,EACrB,oBAAqB,MACrB,oBAAqB,IACrB,iBAAkB,MAClB,iBAAkB,IAGtB,2CAGI,eAAgB,OAIhB,MAAO,KACP,OAAQ,KACR,OAAQ,IAAI,MAAM,KAGtB,mBACI,QAAS,IACT,WAAY,OAGhB,2BACI,eAAgB,KAChB,QAAS,KAUb,wBACI,OAAQ"}
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
@@ -27,6 +27,8 @@ define([
this._el.addClass('log-viewer');
this.editor.setTheme('ace/theme/twilight');
this.editor.setShowPrintMargin(false);
this.editor.renderer.setScrollMargin(0, 75);
this.addKeyListeners();
// Override the textlayer to add support for ansi colors
this.customizeAce();
@@ -34,6 +36,24 @@ define([
_.extend(LogViewerWidget.prototype, TextEditorWidget.prototype);
LogViewerWidget.prototype.addKeyListeners = function() {
// Need to add key listeners to the container itself since ace is in read-only mode
this._el.on('keydown', event => {
// ctrl-alt-pagedown -> EOF
if (event.key === 'PageDown' && event.altKey && (event.ctrlKey || event.metaKey)) {
this.editor.gotoLine(Infinity);
event.stopPropagation();
event.preventDefault();
}
// ctrl-alt-pagedown -> beginning of file
if (event.key === 'PageUp' && event.altKey && (event.ctrlKey || event.metaKey)) {
this.editor.gotoLine(0);
event.stopPropagation();
event.preventDefault();
}
});
};
LogViewerWidget.prototype.getHeader = function(desc) {
return `Console logging for Operation "${desc.name}":\n`;
};
@@ -64,7 +84,7 @@ define([
// Get the editor text and update wrt ansi colors
LogViewerWidget.renderAnsiFromText = function(remaining) {
var r = /\[0(;3([0-7]))?m/,
var r = /\[[0-6][0-9]?(;[0-9]([0-7]))?m/,
match,
ansiCode,
text,
@@ -77,7 +97,9 @@ define([
match = remaining.match(r);
if (match) {
ansiCode = match[0];
nextColor = ANSI_COLORS[match[2]] || null;
if (match[1] && match[1][1] === '3') { // foreground color
nextColor = ANSI_COLORS[match[2]] || null;
}
text = remaining.substring(0, match.index);
remaining = remaining.substring(match.index+ansiCode.length);
} else {
@@ -17,12 +17,17 @@ define([
var MainViewWidget,
WIDGET_CLASS = 'main-view',
CreateListItem = _.template(ListItem);
CreateListItem = _.template(ListItem),
ToggleLabels = [
'Executions',
'Pipelines'
];
MainViewWidget = function (logger, container) {
this._logger = logger.fork('Widget');
this.$el = container;
this.$el.addClass(WIDGET_CLASS);
this.toggleIndex = 0;
this.initialize();
this._logger.debug('ctor finished');
};
@@ -32,6 +37,19 @@ define([
this.$nav = $(NavBarHTML);
this.$el.append(this.$nav);
// Execution support
this.$toggle = this.$nav.find('#toggle-main');
this.$toggleLabel = this.$nav.find('.toggle-label');
this.$toggle.on('click', () => {
if (this._closed) { // shouldn't be clicked when closed (but it is possible)
return;
}
this.toggleEmbeddedPanel();
// Update the toggle name
this.toggleIndex = (this.toggleIndex + 1) % 2;
this.$toggleLabel.text(ToggleLabels[this.toggleIndex]);
});
this.$archlist = this.$nav.find('#arch-list-content');
this.$artifacts = this.$nav.find('#artifact-list-content');
@@ -1,6 +1,13 @@
<nav class="side-nav fixed closed hide-list">
<li class="pull-right side-nav-control">
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
</li >
<li class="no-padding" id="toggle-main">
<ul>
<li class="no-padding">
<a class="toggle-label">Executions</a>
</li>
</ul>
</li>
<li class="no-padding">
<ul class="collapsible" data-collapsible="accordion">
@@ -1,3 +1,7 @@
.main-view-embedded {
position: absolute;
}
.main-view .side-nav-control {
padding-right: 1em;
padding-top: 1em;
@@ -1,10 +1,6 @@
/*globals define */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 12:00:46 GMT-0500 (CDT).
*/
define([
'widgets/TextEditor/TextEditorWidget',
'underscore',
@@ -21,6 +17,15 @@ define([
OperationCodeEditorWidget = function (logger, container) {
TextEditorWidget.call(this, logger, container);
this.lineOffset = 0;
// Add the shift-enter command
this.editor.commands.addCommand({
name: 'executeOrStopJob',
bindKey: {
mac: 'Shift-Enter',
win: 'Shift-Enter'
},
exec: () => this.executeOrStopJob()
});
};
_.extend(OperationCodeEditorWidget.prototype, TextEditorWidget.prototype);
@@ -46,7 +51,7 @@ define([
header.push('-- The following will be executed when the operation is run:');
// Add info about outputs
outputs = desc.outputs.map(pair => `-- ${pair[0]} = <some ${pair[1]}>`)
outputs = desc.outputs.map(pair => `-- ${pair[0]} = <${pair[1]}>`)
.join('\n');
if (outputs.length) {
@@ -80,5 +85,27 @@ define([
this.editor.setOption('firstLineNumber', actualOffset);
};
OperationCodeEditorWidget.prototype.getCompleter = function () {
var completer = TextEditorWidget.prototype.getCompleter.call(this),
getBasicCompletions = completer.getCompletionsFor,
self = this;
completer.getCompletionsFor = function(obj) {
if (obj === 'attributes') {
return self.getOperationAttributes().map(attr => {
return {
name: attr,
value: attr,
score: 4,
meta: 'operation'
};
});
} else {
return getBasicCompletions.apply(this, arguments);
}
};
return completer;
};
return OperationCodeEditorWidget;
});
@@ -1,4 +1,4 @@
/*globals define */
/*globals define*/
define([
'widgets/EasyDAG/DAGItem',
'underscore'
@@ -13,6 +13,7 @@ define([
// Show the warnings
this.$warning = null;
this.updateWarnings();
};
_.extend(Item.prototype, DAGItem.prototype);
@@ -29,38 +30,55 @@ define([
if (this.desc.used === false) {
this.warn(msg, isInput ? 'bottom' : 'top');
} else {
this.clearWarning();
this.clearNotification('$warning');
}
if (this.desc.isUnknown) { // ptrs only
this.error('Unknown type! Click to set', 'bottom');
} else if (this.$error) {
// Set the baseName tooltip, if needed
this.clearNotification('$error');
this.decorator.enableTooltip(this.desc.baseName, 'dark');
}
};
Item.prototype.warn = function(message, tipJoint) {
// Create a temporary div over the given svg element
if (this.$warning) {
this.clearWarning();
}
this.notify(message, '$warning', '#ffeb3b', 'standard', tipJoint);
};
this.decorator.highlight('#ffeb3b');
this.$warning = this.createTooltip(message, {
Item.prototype.error = function(message, tipJoint) {
this.notify(message, '$error', '#ef5350', 'alert', tipJoint);
};
Item.prototype.notify = function(message, varname, color, style, tipJoint) {
this.clearNotification(varname);
this.decorator.highlight(color);
this[varname] = this.createTooltip(message, {
showIf: () => !this.isSelected(),
tipJoint: tipJoint,
style: 'standard'
style: style
});
};
Item.prototype.clearWarning = function() {
if (this.$warning) {
this.destroyTooltip(this.$warning);
this.$warning = null;
Item.prototype.clearNotification = function(varname) {
if (this[varname]) {
this.destroyTooltip(this[varname]);
this[varname] = null;
}
this.decorator.unHighlight();
};
Item.prototype.onSelect = function() {
DAGItem.prototype.onSelect.call(this);
if (this.$warning) {
this.$warning.hide();
}
// Add click listener to set type
if (this.desc.isUnknown) {
this.onSetRefClicked(this.desc.name);
}
};
Item.prototype.setupDecoratorCallbacks = function() {
@@ -37,7 +37,7 @@ define([
EasyDAG.prototype.setupItemCallbacks.call(this);
// Add ptr rename callback
this.ItemClass.prototype.changePtrName = (from, to) => this.changePtrName(from, to);
this.ItemClass.prototype.onSetRefClicked = OperationInterfaceEditorWidget.prototype.onSetRefClicked.bind(this);
};
OperationInterfaceEditorWidget.prototype.onAddItemSelected = function(selected, isInput) {
@@ -77,6 +77,25 @@ define([
this.active = true; // keep refreshing the screen -> it is always visible
};
OperationInterfaceEditorWidget.prototype.onSetRefClicked = function(name) {
var refs = this.allValidReferences();
// Get all valid references
if (refs.length > 1) {
// Create the modal view with all possible subsequent nodes
var dialog = new AddNodeDialog();
dialog.show(null, refs);
dialog.onSelect = selected => {
if (selected) {
this.setRefType(name, selected.node.id);
}
};
} else if (refs[0]) {
this.setRefType(name, refs[0].node.id);
}
};
OperationInterfaceEditorWidget.prototype.onAddRefClicked = function() {
var refs = this.allValidReferences();
@@ -100,5 +119,12 @@ define([
this.addRefTo(target.node.id);
};
OperationInterfaceEditorWidget.prototype.addConnection = function(desc) {
EasyDAG.prototype.addConnection.call(this, desc);
// Remove connection selection
var conn = this.connections[desc.id];
conn.$el.on('click', null);
};
return OperationInterfaceEditorWidget;
});

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais