Comparar commits

..

130 Commits

Autor SHA1 Mensagem Data
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
Brian Broll 96edd6c825 v0.10.1 2016-07-26 10:25:31 -05:00
Brian Broll 4c4b2b02e2 Update README.md 2016-07-25 20:59:46 -05:00
Brian Broll 428a0ec92e Updated install script for cli. Fixes #546 (#551)
WIP #546 Updated install script

WIP #546 Changed install url temporarily

WIP #546 Removed torch install from install script

WIP #546

WIP #546 cd -> process.chdir

WIP #546 Fixed branch in url

WIP #546 Removed default git installation
2016-07-25 20:44:13 -05:00
Brian Broll b0679ae5d8 Replaced unlink w/ rimraf. Fixes #549 (#550)
WIP #549 Fixed bug in tests
2016-07-25 16:29:50 -05:00
Brian Broll bf3fe1ffcd Set 'cwd' for npm commands. Fixes #547 (#548) 2016-07-25 16:19:48 -05:00
Brian Broll d88b758f43 v0.10.0 2016-07-25 12:05:58 -05:00
Brian Broll 0e6ae8f9b6 Added deepforge management cli. Fixes #526 (#545)
WIP #526 Added update command

WIP #526 Added start command

WIP #488 Added mongo detection

WIP #526 Added torch checking & installation

WIP #526 Added help if no args and 'mongodb not installed' msg

WIP #526 Made mongo check into a promise

WIP #526 Made mongodb dir customizable

WIP #526 Config getting/setting

WIP #526 Fixed mongodb starting/checking

WIP #526 Added --torch to update cmd

WIP #526 Added uninstall command

WIP #526 Added --server opt to update and updated package.json

WIP #526 Added eslintrc for bin scripts

WIP #526 minor description fix

WIP #526 Fixed missing dependency

WIP #526 Added some cli test boilerplate

WIP #526 Added cli tests
2016-07-25 12:03:31 -05:00
Brian Broll 3426a07096 Added graphing support in operations/jobs. Fixes #488 (#543)
WIP #488 Added logs for graph plotting

WIP #488 Added graph creation from cmdline logs

WIP #488 Fixed JobEditor bugs exposed by metadata

WIP #488 Removed old metadata on ExecuteJob

WIP #488 Moved graph points to graph attribute

WIP #488 Removed extra whitespace in points

WIP #488 Fixed graph id collisions between jobs

WIP #488 Created OutputViewer

WIP #488 Added filtering for the metadata nodes

WIP #488 Fixed visibility

WIP #488 Adding auto hide when not relevant

WIP #488 remove entries from pagination on delete

WIP #488 Added initialization to the LineGraph

WIP #488 Added LineGraph viz boilerplate

WIP #488 Added basic linegraph

WIP #488 Set LineGraph to use the 'Graph' node

WIP #488 Fixed double-playing commands

WIP #488 Fixed graph sizing and showing in the outputviewer

WIP #488 Adding metadata updating support

WIP #488 Updating graph w/ new data

WIP #488 Added some multi-line support

WIP #488 Added mult-line support for LineGraph

WIP #488 Added Graph metadata type

WIP #488 Fixed 'No Data Available' on quick graph open

WIP #488 revert to console if active graph deleted

WIP #488 Fixed graph update error

WIP #488 Fixed JobEditor nodeId checking

WIP #488 Removed 'points' from Graph

WIP #488 Filtered out deepforge commands from stdout

WIP #488 Fixed filtering deepforge cmds

WIP #488 Fixed ExecutePipeline

WIP #488 Added nvd3 to codeclimate ignore

WIP #488. better error handling for incorrect node types

WIP #488 Removed extra files and fixed code climate issues
2016-07-22 21:12:05 -05:00
Brian Broll e95f611b79 Fixed side-effects to ast on var usage detection. Fixes #538 (#539) 2016-07-20 20:59:43 -05:00
Brian Broll 5d0f13c5ec Moved default execution management to server. Fixes #363 (#537)
WIP #363 Fixed plugin execution on server

WIP #363 Changed primary execution env to the server

WIP #363 Set initial pipeline execution to be on server
2016-07-20 18:39:35 -05:00
Brian Broll 88e1f3828e Removed lineOffset from pipeline editor ops. Fixes #535 (#536) 2016-07-20 09:43:43 -05:00
Brian Broll 4de9cf29fe Retrieved all attribute names (inc reserved names). Fixes #533 (#534) 2016-07-20 08:37:19 -05:00
Brian Broll 448616be12 Hide 'lineOffset' in operation interface editor. Fixes #531 (#532)
WIP #531 Created Constants for lineOffset

WIP #531 Removed 'lineOffset' from visible op node attr
2016-07-20 08:24:56 -05:00
Brian Broll 93a2905534 Set shiftKey check for secondary exec env. Fixes #528 (#530)
WIP #528 Fixed code climate issue
2016-07-19 12:40:24 -05:00
Brian Broll 0bd0bd70f2 Removed dialog from restart execution button. Fixes #524 (#529)
WIP #524 Added restart execution button

WIP #524 Removed 'ExecPipeline' from Executions
2016-07-19 11:04:29 -05:00
Brian Broll 1720fc869a Correct op code line numbers in job editor. Fixes #229 (#527)
WIP #229 Added line number offset support to viz's

WIP #229 Store line offset when generating the op main file

WIP #229 Added 'lineOffset' to 'Operation'

WIP #229. Fixing code climate issues
2016-07-19 10:38:30 -05:00
Brian Broll 41e7750dd1 Created JobEditor for non-snapshotted executions. Fixes #364 (#525)
WIP #364 Created ExecuteJob plugin

WIP #364 ExecutePipeline working again

WIP #364 Added restart job fn-ality

WIP #364 Fixed job status updating

WIP #364 Added JobEditor

WIP #364 Fixed class deserialization

WIP #364 Update exec status on job complete

WIP #364 Fixed JobEditor view for snapshotted jobs

WIP #364 Updated seeds

WIP #364 verify current node is Job

WIP #364 Fixed code climate issues

WIP #364 Fixed some code duplication
2016-07-19 09:44:06 -05:00
Brian Broll 81afc81887 Added unused output detection. Fixes #518 (#522)
WIP #518 Fixed usage update
2016-07-18 21:21:31 -05:00
Brian Broll 3e9931fa3b Added better error handing for invalid lua in op. Fixes #520 (#521)
WIP #520 removed usage info on ptr delete
2016-07-18 20:16:27 -05:00
Brian Broll 5135ccef09 v0.9.0 2016-07-18 08:39:49 -05:00
Brian Broll 6314e00a8d Fixed the attribute shown in deserialize viz. Fixes #512 (#517) 2016-07-17 21:10:22 -05:00
Brian Broll 779429e24d Fixed obj changed pass thru in main view. Fixes #513 (#514) 2016-07-17 20:34:15 -05:00
Brian Broll a7f4eac09d Updated arch editor tooltip init. Fixes #515 (#516) 2016-07-17 20:34:01 -05:00
Brian Broll 7c645e9b23 Added unused op input warning. Fixes #499 (#511)
WIP #499 Added unused input detection

WIP #499. Added input highlight updating on code change

WIP #499 Added warning tooltip and fixed removal

WIP #499 Fixed warning location on position change

WIP #499 Removed unnecessary timeout

WIP #499 Added sophisticated usage checking

WIP #499 Removed code climate issues
2016-07-16 22:42:14 -05:00
Brian Broll fc3e14644f Updated the selObjChanged to update pipeline list. Fixes #507 (#508)
WIP #507 set webgme-autoviz to track master
2016-07-16 15:37:59 -05:00
Brian Broll fd48c1b480 Removed panel padding. Fixes #502 (#506)
WIP #502 Removed padding from the tiling viz's panel
2016-07-16 14:14:11 -05:00
Brian Broll 8928d0f105 Removed old 'code' attr. Fixes #93 (#505) 2016-07-16 13:53:11 -05:00
Brian Broll 6857da5ac7 Updated webgme-autoviz. Fixes #503 (#504) 2016-07-16 13:40:01 -05:00
Brian Broll fee584cfde Added lenet arch to cifar10 example. Fixes #66 (#501) 2016-07-15 20:13:24 -05:00
Brian Broll 45fcd81739 Added tracking EOF for log viewer. Fixes #304 (#500)
WIP #304 Added scroll to bottom

WIP #304 Added eof detection
2016-07-15 17:48:14 -05:00
Brian Broll d831f5e032 Added ubuntu support to install script. Fixes #395 (#498)
WIP #395 Added ubuntu/arch detection

WIP #395 added manual nvm loading

WIP #395 Added source post-installation instructions

WIP #395 Added ubuntu/arch detection
2016-07-15 16:06:18 -05:00
Brian Broll 65e938f489 Created better execution fork names. Fixes #494 (#496)
Improved execution fork name. Fixes #494
2016-07-15 10:25:33 -05:00
Brian Broll b9b5cea5a1 Added exec fork notification. Fixes #345 (#495) 2016-07-15 10:08:26 -05:00
Brian Broll 6c639376d1 Added attributes to condense for width calc. Fixes #492 (#493) 2016-07-15 09:27:03 -05:00
Brian Broll 58ed3048f8 Updated OperationDecorator transitions. Fixes #490 (#491) 2016-07-15 07:41:00 -05:00
Brian Broll f64492061d Added operation attribute support. Fixes #487 (#489)
WIP #487 Added attr edit/del fn-ality

WIP #487 Added attribute creation

WIP #487 Fixed invalid name list

WIP #487 Fixed code climate issue

WIP #487 Fixed operation only behavoirs

WIP #487 Removed 'code' attribute and added number check

WIP #487 Added scientific notation detection

WIP #487 Updated seeds
2016-07-14 12:19:04 -05:00
Brian Broll 552e71687d Added editors to preload by autoviz. Fixes #479 (#486)
WIP #479 Updated autoviz version
2016-07-13 09:37:29 -05:00
Brian Broll 448de23945 Check if instance exists before invoking ser method. Fixes #484 (#485) 2016-07-11 13:53:25 -05:00
Brian Broll dbd00e5946 Added filter for 'return to' action btns. Fixes #482 (#483) 2016-07-11 13:38:38 -05:00
Brian Broll 4d0b4ae017 Added primitive renaming support (by editing comment). Fixes #444 (#480)
WIP #444 Naming support for SerializeEditor

WIP #444 Added renaming functionality for the deserialize editor

WIP #444 Fixed code climate issues
2016-07-11 13:03:20 -05:00
Brian Broll d6c201cce6 Retrieve the deser fn from source node. Fixes #245 (#478) 2016-07-11 12:12:08 -05:00
Brian Broll b8bc3af524 Escaped quoted operation name in log. Fixes #470 (#475) 2016-07-11 11:48:54 -05:00
Brian Broll 72de1d44da Set inputs/outputs for all nodes in pipeline editor. Fixes #411 (#473) 2016-07-11 10:51:02 -05:00
Brian Broll da6f186b52 Added string, boolean types. Fixes #471 (#474) 2016-07-11 10:50:57 -05:00
Brian Broll 5f1c50beb6 Removed territory on text editor destory. Fixes #409 (#472) 2016-07-11 10:50:52 -05:00
Brian Broll 3a79afbc41 v0.8.0 2016-07-11 10:30:22 -05:00
Brian Broll ba210e4b27 Updated icons. Fixes #406 (#469)
WIP #406 Updated some icons

WIP #406 Updated the terminal icon

WIP #406 Updated operation interface icons

WIP #406 terminal -> monitor icon

WIP #406 Fixed code climate issue
2016-07-09 17:15:44 -05:00
Brian Broll bdb21a5262 Set title to regular case. Fixes #467 (#468) 2016-07-09 16:05:30 -05:00
Brian Broll 4b6471efbc Updated buttons and methods for webgme-easydag update. Fixes #465 (#466)
WIP #465 Updated onAddButtonClicked

WIP #465 Updated callbacks for webgme-easydag update

WIP #465 Fixing code climate issue
2016-07-09 15:42:04 -05:00
JimnyCricket beeb1deb3c Merge pull request #457 from dfst/456-simple-cifar
Split cifar10 example into 4 pipelines. Fixes #456
2016-07-08 17:37:19 -05:00
Brian Broll 0bc6846c32 Optimized the arch editor layer selection. Fixes #78 (#463)
WIP #78 ~3x speedup in arch editor

WIP #78 Removed unused var
2016-07-08 10:00:47 -06:00
Brian Broll 8a40cb95fb Updated and configured breadcrumbheader. Fixes #441 (#462) 2016-07-08 07:29:45 -06:00
Brian Broll 92ea4b2ff5 Removed ptrs from op desc in OpIntEditor. Fixes #433 (#461) 2016-07-07 17:48:56 -06:00
Brian Broll e0a83b4d6c Added 'print', 'SGD' ops. Fixes #368 (#460) 2016-07-07 17:41:58 -06:00
Brian Broll 49268b9554 Fixed arch update on main screen. Fixes #458 (#459) 2016-07-07 17:41:51 -06:00
Brian Broll 65164bcb76 Merge branch 'master' into 456-simple-cifar 2016-07-07 17:31:43 -05:00
Brian Broll 1afcaf9238 Split cifar10 example into 4 pipelines. Fixes #456 2016-07-07 17:30:34 -05:00
Brian Broll 92021a06ba Decreased cifar10 max iterations. Fixes #424 (#455) 2016-07-07 15:48:18 -06:00
Brian Broll be1e4fa388 Added 'Data' to op input options. Fixes #376 (#454)
WIP #376 Removed 'Data' from output options
2016-07-07 15:17:27 -06:00
JimnyCricket 09505c9989 Clears jobs on restart of server Fixes #452 (#453) 2016-07-07 14:57:34 -06:00
Brian Broll b96f2a845a Added criterion reference support. Fixes #369 (#450)
WIP #369 Removed criterion filter

WIP #396 Added criterion layers to nn seed

WIP #369 Added GenerateCriterion plugin

WIP #369 Added GenerateCriterion to criterion meta

WIP #369 Filtered criterion from the ArchEditor

WIP Removed old css

WIP #369 filtered criterion types

WIP #369. Fixed criterion pointer assignment

WIP #369 Fixed criterion execution problems

WIP #369 Updated seeds

WIP #369 Fixed failing test
2016-07-07 11:54:09 -06:00
Brian Broll 14c0af86c9 Added import torch action to arch editor. Fixes #447 (#449) 2016-07-07 10:29:13 -06:00
Brian Broll 56a0b788ee Added editable title for architecture. Fixes #445 (#448)
WIP #445 Refactoring the panel title renaming

WIP #445 Made arch editor renameable

WIP #445 Fixed capitalization for consistency
2016-07-07 10:28:54 -06:00
Brian Broll 873cbc2145 Updated main view to have nav bar and pipeline index. Fixes #440 (#446)
WIP #440 Added MainView

WIP #440 Removed unneeded files

WIP #440 Added basic left bar

WIP #440 Added root node actions

WIP #440 Embedded PipelineIndex

WIP #440 Removed unused js

WIP #440 Removed setTimeout

WIP #440 Fixed some layout issues. css reduction

WIP #440 Added glyphicon

WIP #440 Fixed menu control icon placement, size, color

WIP

WIP #440 Added opening/closing of the nav bar

WIP #440 Added grey background-color

WIP #440 Fixed hide on small screens

WIP #440. Added action buttons

WIP #440 Fixed arch-content list

WIP #440 Removed bullet points

WIP #440 Fixed resize positioning

WIP #440 Increased font size for headers

WIP #440 italic actions

WIP #440 Added some structure for the artifacts

WIP #440 Added download artifact link

WIP #440 Fixed lingering territory rules

WIP #440 removed unused lib files

WIP #440 Fixed code climate issues
2016-07-07 09:21:35 -06:00
Brian Broll 3e3326688c Added meaningful error if retrieving nil val from layer. Fixes #386 (#442)
WIP #386 Added googlenet-setters for testing error messages

WIP #386 Commented out tacking in extra values

WIP #386 Ignore "nil gets" if in "set" operation
2016-07-01 13:14:06 -05:00
Brian Broll 6e32394e01 Added pipeline index viz. Fixes #429 (#438)
WIP #429 Added basic boilerplate for the pipeline index viz

WIP #429 Removed the title

WIP #429 Fixed columns (and text)

WIP #429 Added open, delete actions

WIP #429 Added double click to edit pipeline name

WIP #429 Added check for empty, same name

WIP #429 Added comment for thing to add next

WIP #429 Added some thumbnail support and embedded support

WIP #429 Fixed the thumbnail

WIP #429 thumbnail updates

WIP #429 Set background color and fixed updateNode bug

WIP #429 Fixed update thumbnail deletion

WIP #429 Added preview click-to-open

WIP #429 Added empty message

WIP #429 slight refactor

WIP #429 Added executions text (better phrasing)

WIP #429 Removed toolbar items

WIP #429 Fixed remove undefined bug

WIP #429 Updated seeds

WIP #429 Added pipeline index css to ignore

WIP #429 Fixed code climate issues

WIP #429 Added csslint ignore file

WIP #429 Fixed code climate issues

WIP #429 Added csslint ignore block for materialize

WIP #429 Added thumbnails to cifar10 example
2016-06-30 15:33:05 -05:00
Brian Broll afed957af8 Set artifact loader to remove data handle on "unset". Fixes #437 (#439) 2016-06-30 15:24:42 -05:00
Brian Broll 4c100ac001 Added support for creating primitive types from op editor. Fixes #432 (#435)
WIP #432 Added basic support for primitive/complex coloring and creation

WIP #432 Added tabs
2016-06-30 14:46:06 -05:00
Brian Broll 29724551f0 Updated reference selection btns in op editor. Fixes #434 (#436) 2016-06-29 14:50:18 -05:00
Brian Broll 1f5c8d7423 Updated ImportArtifact result checking. Fixes #427 (#431) 2016-06-29 13:24:18 -05:00
Brian Broll a613a1e8f7 Added artifact upload from ArtifactLoader. Fixes #422 (#428)
WIP #422 Added upload artifact icon

WIP #422 Added upload artifact functionality
2016-06-29 13:10:09 -05:00
JimnyCricket 7fce6e98dd Merge pull request #426 from dfst/425-port-must-be-num
Casted PORT to num. Fixes #425
2016-06-29 11:04:09 -07:00
Brian Broll ea572e8f6c Casted PORT to num. Fixes #425 2016-06-29 12:26:24 -05:00
Brian Broll 36290d8dc7 Removed the data type card. Fixes #420 (#421) 2016-06-29 09:32:50 -05:00
Brian Broll dadc09e0e1 Added delete, return-to-op fab actions for Primitive editing. Fixes #418 (#419) 2016-06-29 09:07:17 -05:00
Brian Broll be3d278d13 Added GoToBase btn for data in op editor. Fixes #414 (#417) 2016-06-29 09:00:22 -05:00
Brian Broll 32a96fbf2b Added class def -> op editor pivots and del btn. Fixes #413 (#416)
WIP #413. Fixed code climate issue
2016-06-29 08:51:38 -05:00
Brian Broll ebe391c948 Added 'Create Class' node in OperationEditor. Fixes #171 (#415)
WIP #171 Adding support for new classes

WIP #171. Fixed "New Class" tooltip

WIP #171 Fixed eslint error
2016-06-29 08:41:15 -05:00
Brian Broll e30ebf3a45 Added os not recognized message. Fixes #404 (#405)
WIP #404 Added "install mongo" message at end

WIP #404 Fixed message when mongo installed
2016-06-28 15:43:37 -05:00
Brian Broll 9e0a780ed2 Updated new op name to conform to new layer name. Fixes #399 (#403) 2016-06-28 15:17:58 -05:00
Brian Broll 841637e804 Updated plugin names and icons. Fixes #401 (#402) 2016-06-28 15:01:44 -05:00
Brian Broll 75241262c4 Added delete custom layer def. Fixes #389 (#400)
WIP #389 code climate fix
2016-06-28 14:37:40 -05:00
Brian Broll b39ac022b6 Added operation deletion button. Fixes #390 (#398)
WIP #390 Added delete button (non-func)

WIP #390 Added deletion func for deleting current node
2016-06-28 14:20:05 -05:00
Brian Broll 8486b86a05 Added pivot back to last arch from custom layer. Fixes #388 (#396)
WIP #388 Refactored op -> pipeline pivoting
2016-06-28 13:53:36 -05:00
Brian Broll 322af8a4f5 Removed 'MyLayers' card. Fixes #391 (#394) 2016-06-28 13:39:49 -05:00
Brian Broll 5e1930f096 Added tabs to initial layer dialog. Fixes #392 (#393) 2016-06-28 13:09:28 -05:00
Brian Broll c0f1348a14 Added sponsor info and removed caffe support comment 2016-06-28 13:06:35 -05:00
Brian Broll 383f5f9fa0 Added (tabbed) custom layer creation from arch editor. Fixes #385 (#387)
WIP #385 Added node icons to arch creator.

WIP #385 Updated for new AddNodeDialog.prompt interface

WIP #385 Added tabs to layers and create layer support

WIP #385 Added code climate ignore dup (non) issue

WIP Added codeclimate, csslint configs
2016-06-28 10:50:40 -05:00
Brian Broll 5cf592e103 removed old 'demo' seed. Fixes #365 (#384) 2016-06-28 07:46:26 -05:00
Brian Broll a14e750b6f Made pipeline title editable. Fixes #375 (#383) 2016-06-27 16:12:25 -05:00
Brian Broll 73e165197f Added editable operation title & better header comment. Fixes #380 (#381)
WIP #380 Added editable title

WIP #380 Updated the operation header comment

WIP #380 Fixed code climate warning
2016-06-27 14:26:59 -05:00
Brian Broll 9dd0815625 Auto-remove dangling connections in pipelines. Fixes #377 (#382) 2016-06-27 14:26:51 -05:00
Brian Broll 8e3ac1d203 Removed Ops, Execs cards from root view. Fixes #373 (#379) 2016-06-27 13:45:32 -05:00
1164 arquivos alterados com 341810 adições e 21798 exclusões
+36
Ver Arquivo
@@ -0,0 +1,36 @@
---
engines:
csslint:
enabled: true
duplication:
enabled: true
exclude_fingerprints:
- 1e004cf4e49528a58a0ac3858112601c
config:
languages:
- ruby
- javascript
- python
- php
eslint:
enabled: true
fixme:
enabled: true
ratings:
paths:
- "**.css"
- "**.inc"
- "**.js"
- "**.jsx"
- "**.module"
- "**.php"
- "**.py"
- "**.rb"
exclude_paths:
- config/
- test/
- src/common/lua.js
- src/common/js-yaml.min.js
- src/visualizers/widgets/TextEditor/lib/
- src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
- src/visualizers/widgets/LineGraph/lib/
+3
Ver Arquivo
@@ -0,0 +1,3 @@
--exclude-exts=.min.css
--exclude-list=src/visualizers/widgets/PipelineIndex/styles/PipelineIndex.css
--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
+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"
+6 -7
Ver Arquivo
@@ -1,10 +1,10 @@
[![Release State](https://img.shields.io/badge/state-alpha-orange.svg)](https://img.shields.io/badge/state-alpha-orange.svg)
[![Release State](https://img.shields.io/badge/state-beta-yellow.svg)](https://img.shields.io/badge/state-beta-yellow.svg)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE)
[![Build Status](https://travis-ci.org/dfst/deepforge.svg?branch=master)](https://travis-ci.org/dfst/deepforge)
[![Join the chat at https://gitter.im/dfst/deepforge](https://badges.gitter.im/dfst/deepforge.svg)](https://gitter.im/dfst/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Stories in Ready](https://badge.waffle.io/dfst/deepforge.png?label=ready&title=Ready)](https://waffle.io/dfst/deepforge)
**Notice**: DeepForge is still very much a work in progress and is also lacking significant documentation! That being said, any contributions and/or feedback is greatly appreciated (and feel free to always ask any questions on the gitter)!
**Notice**: DeepForge is still a work in progress and is also lacking significant documentation! That being said, any contributions and/or feedback is greatly appreciated (and feel free to always ask any questions on the gitter)!
# DeepForge
DeepForge is an open-source visual development environment for deep learning. Currently, it supports Convolutional Neural Networks but we are planning on supporting additional deep learning classifiers such as RNNs and LSTMs. Additional features include real-time collaborative editing and version control.
@@ -16,12 +16,11 @@ Simply run the following command to install deepforge with its dependencies:
curl -o- https://raw.githubusercontent.com/dfst/deepforge/master/install.sh | bash
```
Next, follow the postinstall instructions to start MongoDB and 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).
## Caffe Support?
DeepForge uses Torch to perform the actual training and testing of the models. If you are interested in DeepForge using Caffe for actual training and testing, check out [DeepForge-Caffe](https://github.com/dfst/deepforge-caffe).
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).
## Interested in contributing?
Contributions are welcome! Either fork the project and submit some PR's or shoot me an email about getting more involved!
Sponsored by [Digital Reasoning](http://www.digitalreasoning.com/)
+21
Ver Arquivo
@@ -0,0 +1,21 @@
env:
browser: true
node: true
mocha: true
es6: true
extends: 'eslint:recommended'
rules:
no-console:
- 0
indent:
- 2
- 4
linebreak-style:
- 2
- unix
quotes:
- 2
- single
semi:
- 2
- always
+8
Ver Arquivo
@@ -0,0 +1,8 @@
{
"torch": {
"dir": "~/.deepforge/torch"
},
"mongo": {
"dir": "~/.deepforge/data"
}
}
Arquivo executável
+404
Ver Arquivo
@@ -0,0 +1,404 @@
#!/usr/bin/env node
var Command = require('commander').Command,
program = new Command(),
childProcess = require('child_process'),
spawn = childProcess.spawn,
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'),
config,
configDir = path.join(process.env.HOME, '.deepforge'),
configPath = path.join(configDir, 'config.json'),
dataPath = path.join(configDir, 'data'),
localConfig,
rm_rf = require('rimraf'),
p = dir => dir.replace(/^~/, process.env.HOME); // resolve '~' to '$HOME'
// Check for any commands
if (process.argv.length === 2) {
process.argv.push('--help');
}
// Create the config if it doesn't exist
if (!exists.sync(configDir)) {
fs.mkdirSync(configDir);
}
if (!exists.sync(dataPath)) {
fs.mkdirSync(dataPath);
}
if (!exists.sync(configPath)) {
fs.writeFileSync(configPath, '{\n}');
}
localConfig = require(configPath);
config = assign(DEFAULT_CONFIG, require(configPath));
var getConfigValue = function(id) {
var keys = id.split('.'),
value = config;
for (var i = 0; i < keys.length; i++) {
value = value[keys[i]];
if (!value) {
return null;
}
}
return value;
};
var storeConfig = function(id, value) {
// load the config
var keys = id.split('.').filter(k => k),
lastKey = keys.pop(),
currentObj = localConfig,
current = getConfigValue(id);
// Check if it is a valid key
if (current === null) {
return false;
}
for (var i = 0; i < keys.length; i++) {
if (!currentObj[keys[i]]) {
currentObj[keys[i]] = {};
}
currentObj = currentObj[keys[i]];
}
currentObj[lastKey] = value;
fs.writeFileSync(configPath, JSON.stringify(localConfig, null, 2));
return true;
};
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;
};
var checkMongo = function(args) {
// check the webgme config
var gmeConfig = require('../config'),
mongoUri = gmeConfig.mongo.uri;
if (isLocalUri('mongodb', mongoUri)) {
// Make sure mongo is running locally (using pgrep)
try {
execSync('pgrep mongod').toString();
console.log('MongoDB is already running!');
} catch (e) { // no pIds
console.log('Starting MongoDB...');
startMongo(args, true);
}
}
};
var startMongo = function(args, silent) {
var job = spawn('mongod', ['--dbpath', p(config.mongo.dir)], {
cwd: process.env.HOME
});
if (!silent) {
job.stdout.on('data',
data => process.stdout.write(data.toString()));
}
job.on('error', err => {
if (err.code === 'ENOENT') {
console.log('Could not find MongoDB. Is it installed?');
if (!args.mongo) {
console.log('Otherwise, set MONGO_URI to the desired mongo uri and try again:');
console.log('');
console.log(' MONGO_URI=mongodb://some.other.ip:27017' +
`/deepforge deepforge ${process.argv.slice(2).join(' ')}`);
console.log('');
}
} else {
console.log('Error encountered while starting MongoDB');
throw err;
}
});
job.stderr.on('data', data => {
var msg = 'mongodb: ' + data;
process.stdout.write(msg);
});
job.on('exit', code => {
if (code) {
console.log('MongoDB closed w/ error code: ' + code);
}
});
};
var checkTorch = function() {
return new Promise(_checkTorch)
.catch(() => 'Torch installation failed');
};
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`;
if (result.error) {
// Try to install torch
console.log(`Torch7 not found. Installing to ${tgtDir}...`);
spawnMany([gcl],
() => {
process.chdir(tgtDir);
spawnMany([
'bash install-deps',
'./install.sh'
], () => {
storeConfig('torch.dir', tgtDir);
resolve(true);
}, reject);
},
reject
);
} else {
resolve(false);
}
};
var spawnMany = function(cmds, succ, err) {
var rawCmd,
cmd,
args,
job;
if (cmds.length === 0) {
return succ();
}
rawCmd = cmds.shift();
args = rawCmd.split(' ');
cmd = args.shift();
job = spawn(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);
} else {
spawnMany(cmds, succ, err);
}
});
};
program.command('start')
.description('start deepforge locally (default) or specific components')
.option('-p, --port <port>', 'specify the port to use')
.option('-s, --server', 'start the server')
.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: []
};
if (args.port) {
opts.env = {
PORT: args.port
};
}
if (args.server) {
checkMongo(args);
main = path.join(__dirname, '..', 'app.js');
start(main, opts);
}
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 (args.mongo) {
startMongo(args);
}
if (!args.server && !args.worker && !args.mongo) {
// Starting everything
checkMongo(args);
checkTorch().then(() => start(main, opts));
}
});
// update
program
.command('update')
.description('upgrade deepforge to latest version')
.option('-g, --git', 'update tracking the git repo')
.option('-t, --torch', 'update torch installation')
.option('-s, --server', 'update deepforge')
.action(args => {
var pkg = 'deepforge',
job,
latestVersion;
// Install the project
if (!args.torch || args.server) {
if (args.git) {
pkg = 'dfst/deepforge';
} else {
// Check the version
try {
latestVersion = execSync('npm show deepforge version')
.toString().replace(/\s+$/, '');
if (latestVersion === version) {
console.log('Already up-to-date');
return;
}
} catch (e) {
console.log('Could not retrieve the latest deepforge version');
}
}
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) {
console.log('Upgrade successful!');
} else {
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...');
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;
}
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);
}
});
}
});
}
});
// uninstall command
program
.command('uninstall')
.description('uninstall deepforge from the system')
.option('-t, --torch', 'uninstall torch')
.option('-c, --clean', 'uninstall deepforge, torch and all associated data/config')
.action(opts => {
if (opts.torch || opts.clean) {
if (opts.torch) {
console.log(`uninstalling torch at ${p(config.torch.dir)}`);
}
rm_rf.sync(p(config.torch.dir));
}
if (opts.clean) { // remove the .deepforge directory
console.log('removing config and data files...');
rm_rf.sync(p(config.mongo.dir));
rm_rf.sync(p(configDir));
}
if (!opts.torch || opts.clean) { // uninstall deepforge
spawnMany(
['npm uninstall -g deepforge'],
() => console.log('deepforge has been uninstalled!'),
() => console.log('uninstall failed')
);
}
});
// config
program
.command('config [key] [value]')
.description('read or edit config options (omit "value" to see current value)')
.action(key => {
var value = program.args[1],
success;
if (value) { // write a value
success = storeConfig(key, value);
if (success) {
console.log('Config has been updated!');
}
} else if (key) { // read a single value
value = getConfigValue(key);
if (value === null) {
console.log(`Invalid config value: "${key}"`);
return;
}
if (typeof value === 'object') {
value = JSON.stringify(value, null, 2);
}
console.log(value);
} else { // print entire config
console.log(`Current config:\n${JSON.stringify(config, null, 2)}`);
}
});
module.exports = function(cmd) {
var cmds = cmd.split(/\s+/).filter(w => !!w);
cmds.unshift('node');
cmds.unshift('./bin/deepforge');
program.parse(cmds);
};
if (require.main === module) {
program.parse(process.argv);
}
+4 -2
Ver Arquivo
@@ -2,12 +2,14 @@
var spawn = require('child_process').spawn,
stdout = '',
execJob,
path = require('path'),
env = {cwd: path.join(__dirname, '..')},
workerJob = null;
process.env.NODE_ENV = 'local';
execJob = spawn('npm', [
'start'
]);
], env);
execJob.stdout.pipe(process.stdout);
execJob.stderr.pipe(process.stderr);
@@ -15,7 +17,7 @@ execJob.stdout.on('data', function(chunk) {
if (!workerJob) {
stdout += chunk;
if (stdout.indexOf('DeepForge') > -1) {
workerJob = spawn('npm', ['run', 'worker']);
workerJob = spawn('npm', ['run', 'worker'], env);
workerJob.stdout.pipe(process.stdout);
workerJob.stderr.pipe(process.stderr);
workerJob.on('close', code => code && process.exit(code));
+10 -2
Ver Arquivo
@@ -4,11 +4,12 @@ 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'),
workerConfigPath = path.join(workerPath, 'config.json'),
workerConfigPath = path.join(workerPath, 'config_' + Date.now() + '.json'),
workerTmp = path.join(workerPath, 'tmp'),
address,
config = {};
@@ -22,7 +23,15 @@ if (result.error) {
process.exit(1);
}
var cleanUp = function() {
console.log('removing config ', workerConfigPath);
rm_rf.sync(workerConfigPath);
};
var startExecutor = function() {
process.on('SIGINT', cleanUp);
process.on('uncaughtException', cleanUp);
// Start the executor
var execJob = spawn('node', [
'node_worker.js',
@@ -42,7 +51,6 @@ var createConfigJson = function() {
}
config[address] = {};
// TODO: Check if the config already exists
fs.writeFile(workerConfigPath, JSON.stringify(config), startExecutor);
};
+16 -27
Ver Arquivo
@@ -1,8 +1,19 @@
{
"AutoViz": {
"preloadIds": [
"ArchEditor",
"PipelineEditor",
"OperationEditor",
"ExecutionView"
]
},
"ArchEditor": {
"hotkeys": "none",
"LayerColors": {}
},
"BreadcrumbHeader": {
"pathRule": "history"
},
"FloatingActionButton": {
"hideOnEmpty": true
},
@@ -43,48 +54,26 @@
"nodes": [
{
"nodeName": "MyArchitectures",
"title": "Architectures",
"icon": "shuffle",
"rank": 1,
"description": "Neural network architectures are stored here and can be used in pipelines."
},
{
"nodeName": "MyOperations",
"icon": "mode_edit",
"rank": 2,
"color": "blue-grey",
"description": "Operations are the building blocks of pipelines. Custom operations can be created and stored here."
},
{
"nodeName": "MyPipelines",
"title": "Pipelines",
"color": "blue-grey",
"icon": "input",
"rank": 3,
"description": "Pipelines compose operations together to effectively train, test and/or ensemble models."
},
{
"nodeName": "MyLayers",
"icon": "clear_all",
"rank": 4,
"color": "blue-grey",
"description": "Custom torch layers can be created and stored here for use in neural network architectures."
},
{
"nodeName": "MyArtifacts",
"title": "Artifacts",
"icon": "view_quilt",
"color": "blue-grey",
"rank": 5,
"description": "Artifacts from pipeline executions are stored here."
},
{
"nodeName": "MyExecutions",
"icon": "list",
"rank": 6,
"color": "blue-grey",
"description": "Executions are read-only snapshots of pipelines that have been executed. Past and current executing pipelines are stored here."
},
{
"nodeName": "MyDataTypes",
"icon": "settings",
"rank": 7,
"description": "Custom defined data types are stored here."
}
]
}
+5 -1
Ver Arquivo
@@ -7,17 +7,21 @@ var config = require('./config.webgme'),
require('dotenv').load({silent: true});
// Add/overwrite any additional settings here
config.server.port = process.env.PORT || config.server.port;
config.server.port = +process.env.PORT || config.server.port;
config.mongo.uri = process.env.MONGO_URI || config.mongo.uri;
config.requirejsPaths.deepforge = './src/common';
config.requirejsPaths.ace = './src/visualizers/widgets/TextEditor/lib/ace';
config.seedProjects.defaultProject = 'project';
config.plugin.allowBrowserExecution = true;
config.plugin.allowServerExecution = true;
config.executor.enable = true;
config.executor.clearOldDataAtStartUp = true;
config.visualization.extraCss.push('deepforge/styles/global.css');
config.storage.autoMerge.enable = true;
validateConfig(config);
module.exports = config;
+1 -1
Ver Arquivo
@@ -18,9 +18,9 @@ config.seedProjects.basePaths.push('src/seeds/devTests');
config.seedProjects.basePaths.push('src/seeds/devUtilTests');
config.seedProjects.basePaths.push('src/seeds/pipeline');
config.seedProjects.basePaths.push('src/seeds/devPipelineTests');
config.seedProjects.basePaths.push('src/seeds/demo');
config.seedProjects.basePaths.push('src/seeds/project');
config.seedProjects.basePaths.push('src/seeds/cifar10');
config.seedProjects.basePaths.push('src/seeds/xor');
+46 -16
Ver Arquivo
@@ -5,13 +5,6 @@
command -v git >/dev/null 2>&1 || { echo >&2 "I require git but it's not installed. Aborting."; exit 1; }
echo >&2 "Checking DeepForge dependencies...";
command -v th >/dev/null 2>&1 || {
# No torch!
echo >&2 "Torch is not found. Installing...";
git clone https://github.com/torch/distro.git ~/torch --recursive;
cd ~/torch; bash install-deps;
./install.sh;
}
# profile (bash, zsh, profile, etc) borrowed from nvm's installer
detect_profile() {
@@ -53,6 +46,7 @@ command -v node >/dev/null 2>&1 || {
echo >&2 "NodeJS is not found. Installing (using nvm)...";
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash;
source $DETECTED_PROFILE
. $NVM_DIR/nvm.sh
# Install nodejs v6.2.0
echo "Installing nodejs v6.2.0"
@@ -61,7 +55,6 @@ command -v node >/dev/null 2>&1 || {
# Install npm@2
npm install npm@2 -g
}
command -v node >/dev/null 2>&1 || {
@@ -69,18 +62,55 @@ command -v node >/dev/null 2>&1 || {
echo >&2 "MongoDB is not found. Installing...";
if [[ `uname` == "Darwin" ]]; then
brew install mongodb
elif [[ "$(uname)" == 'Linux' ]]; then
if [[ -r /etc/os-release ]]; then
# this will get the required information without dirtying any env state
DIST_VERS="$( ( . /etc/os-release &>/dev/null
echo "$ID $VERSION_ID") )"
DISTRO="${DIST_VERS%% *}" # get our distro name
VERSION="${DIST_VERS##* }" # get our version number
elif [[ -r /etc/lsb-release ]]; then
DIST_VERS="$( ( . /etc/lsb-release &>/dev/null
echo "${DISTRIB_ID,,} $DISTRIB_RELEASE") )"
DISTRO="${DIST_VERS%% *}" # get our distro name
VERSION="${DIST_VERS##* }" # get our version number
else # well, I'm out of ideas for now
echo '==> Failed to determine distro and version.'
exit 1
fi
# Detect archlinux
if [[ "$DISTRO" = "arch" ]]; then
distribution="archlinux"
sudo pacman -S mongodb
# Detect Ubuntu
elif [[ "$DISTRO" = "ubuntu" ]]; then
export DEBIAN_FRONTEND=noninteractive
sudo apt-get install mongodb
else
NEEDS_MONGO=true
fi
fi
}
echo >&2 "Installing DeepForge...";
# Clone deepforge into ~/deepforge
git clone https://github.com/dfst/deepforge ~/deepforge
cd ~/deepforge
npm install
npm install -g deepforge
mkdir ~/deepforge/data 2> /dev/null
echo "DeepForge is installed! To run it:"
echo " 1) make sure MongoDB is running locally"
echo " (start mongo w/ \"mongod --dbpath ~/deepforge/data\")"
echo " 2) Run \"npm run local\" from ~/deepforge"
echo "Final Installation Steps:"
echo " 1) Close and re-open your terminal"
echo " (or run \"source $DETECTED_PROFILE\")"
if [[ $NEEDS_MONGO ]]; then
echo " 2) Install MongoDB for your OS"
echo " (available at https://www.mongodb.com/download-center)"
echo " Note: for custom installs, this may not be required"
fi
echo ""
echo "Then run DeepForge!"
echo " 1) run \"deepforge start\""
echo " 2) open a browser to http://localhost:8888"
echo " 3) start building neural nets!"
+14 -6
Ver Arquivo
@@ -1,5 +1,8 @@
{
"name": "deepforge",
"bin": {
"deepforge": "./bin/deepforge"
},
"scripts": {
"start": "node app.js",
"start-dev": "NODE_ENV=dev node app.js",
@@ -9,23 +12,28 @@
"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.7.0",
"version": "0.12.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",
"nodemon": "^1.9.2",
"webgme": "^2.0.0",
"webgme-autoviz": "^2.0.3",
"webgme-breadcrumbheader": "^2.0.0",
"webgme-autoviz": "dfst/webgme-autoviz",
"webgme-breadcrumbheader": "^2.1.0",
"webgme-chflayout": "^2.0.0",
"webgme-easydag": "dfst/webgme-easydag",
"webgme-fab": "dfst/webgme-fab",
"webgme-simple-nodes": "^2.0.0"
"webgme-simple-nodes": "^2.0.0",
"rimraf": "^2.4.0"
},
"devDependencies": {
"chai": "^3.0.0",
"jszip": "^2.5.0",
"mocha": "^2.2.5",
"rimraf": "^2.4.0",
"chai": "^3.0.0"
"mockery": "^1.7.0"
}
}
+13
Ver Arquivo
@@ -0,0 +1,13 @@
/* globals define */
define({
LINE_OFFSET: 'lineOffset',
// DeepForge metadata creation in dist execution
START_CMD: 'deepforge-cmd',
IMAGE: 'IMG',
GRAPH_CREATE: 'GRAPH',
GRAPH_PLOT: 'PLOT',
GRAPH_CREATE_LINE: 'LINE'
});
+276
Ver Arquivo
@@ -0,0 +1,276 @@
/* 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 findInitParams = function(ast){
// Find '__init' function
var params;
ast.block.stats.forEach(function(block){
if(block.key && block.key.val == '__init' && block.func){
params = block.func.args;
if(params.length === 0 && block.func.varargs){
params[0] = 'params';
}
}
});
return params;
};
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.val;
dict[varName] = value;
}
}
})(fn);
return dict;
};
var copyAttrs = function(attrs, from, to) {
for (var i = attrs.length; i--;) {
to[attrs[i]] = from[attrs[i]];
}
return to;
};
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.', '');
params = findInitParams(ast);
if (torchClassArgs.length > 1) {
baseType = torchClassArgs[1].replace('nn.', '');
}
}
}
});
}
// Get the setters and defaults
var setterNames,
schema,
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);
}
})(ast);
// Get the defaults for the params from defs
if (paramDefs) {
copyAttrs(params, paramDefs, defaults);
}
// Get the defaults for the setters from attrDefs
if (attrDefs) {
setterNames = Object.keys(setters);
copyAttrs(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,
defaults
};
};
LayerParser.parse = function(text) {
var ast = luajs.parser.parse(text);
return findTorchClass(ast);
};
return LayerParser;
}));
+98 -4
Ver Arquivo
@@ -1,10 +1,12 @@
/* 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'
], function(
Materialize,
REGISTRY_KEYS,
META_CONSTANTS,
CONSTANTS
@@ -89,13 +91,14 @@ define([
return name;
};
/////////// Initializing DeepForge ///////////
//////////////////// DeepForge places detection ////////////////////
var TYPE_TO_CONTAINER = {
Architecture: 'MyArchitectures',
Pipeline: 'MyPipelines',
Execution: 'MyExecutions',
Layer: 'MyLayers',
Artifact: 'MyArtifacts',
Operation: 'MyOperations',
Primitive: 'MyDataTypes',
Complex: 'MyDataTypes'
@@ -141,8 +144,7 @@ define([
placesTerritoryId = null;
};
// Add DeepForge action primitives
// Creating custom operations
//////////////////// DeepForge creation actions ////////////////////
var instances = [
'Architecture',
'Pipeline'
@@ -180,6 +182,92 @@ define([
return newId;
};
var createCustomLayer = function(typeName) {
var metanodes = client.getAllMetaNodes(),
msg = `Created new custom ${typeName} layer`,
newId,
customLayerId,
baseId,
name,
i = metanodes.length;
while (i-- && !(baseId && customLayerId)) {
name = metanodes[i].getAttribute('name');
if (name === 'CustomLayer') {
customLayerId = metanodes[i].getId();
} else if (name === typeName) {
baseId = metanodes[i].getId();
}
}
client.startTransaction(msg);
newId = createNamedNode(baseId, DeepForge.places.MyLayers, true);
addToMetaSheet(newId, 'CustomLayers');
client.addMixin(newId, customLayerId);
client.setRegistry(newId, REGISTRY_KEYS.IS_ABSTRACT, false);
client.completeTransaction();
WebGMEGlobal.State.registerActiveObject(newId);
};
// Creating Artifacts
var UPLOAD_PLUGIN = 'ImportArtifact',
DATA_TYPE_CONFIG = {
name: 'dataTypeId',
displayName: 'Data Type Id',
valueType: 'string',
valueItems: []
};
var uploadArtifact = function() {
// Get the data types
var dataBase,
dataBaseId,
metanodes = client.getAllMetaNodes(),
dataTypes = [];
dataBase = metanodes.find(n => n.getAttribute('name') === 'Data');
if (!dataBase) {
this.logger.error('Could not find the base Data node!');
return;
}
dataBaseId = dataBase.getId();
dataTypes = metanodes.filter(n => client.isTypeOf(n.getId(), dataBaseId))
.filter(n => !n.getRegistry('isAbstract'))
.map(node => node.getAttribute('name'));
//this.logger.info(`Found ${dataTypes.length} data types`);
// Add the target type to the pluginMetadata... hacky :/
var metadata = WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN],
config = metadata.configStructure
.find(opt => opt.name === DATA_TYPE_CONFIG.name);
if (!config) {
config = DATA_TYPE_CONFIG;
WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN].configStructure.push(config);
}
config.valueItems = dataTypes;
config.value = dataTypes[0];
WebGMEGlobal.InterpreterManager.configureAndRun(metadata, (result) => {
var msg = 'Artifact upload complete!';
if (!result) {
return;
}
if (!result.success) {
msg = `Artifact upload failed: ${result.error}`;
}
Materialize.toast(msg, 2000);
});
};
DeepForge.last = {};
DeepForge.create = {};
instances.forEach(type => {
DeepForge.create[type] = function() {
@@ -193,10 +281,16 @@ define([
};
});
DeepForge.create.Layer = createCustomLayer;
DeepForge.create.Artifact = uploadArtifact;
//////////////////// DeepForge prev locations ////////////////////
// Update DeepForge on project changed
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_PROJECT_NAME, updateDeepForgeNamespace, null);
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_PROJECT_NAME,
updateDeepForgeNamespace, null);
// define DeepForge globally
window.DeepForge = DeepForge;
return DeepForge;
});
+17 -3
Ver Arquivo
@@ -19,6 +19,10 @@ define([
return arg.hasOwnProperty('argindex');
};
var isSetter = function(arg) {
return arg.hasOwnProperty('setterType');
};
var sortByIndex = function(a, b) {
return a.argindex > b.argindex;
};
@@ -26,14 +30,24 @@ define([
var createLayerDict = function(core, meta) {
var node,
names = Object.keys(meta),
layers = {};
layers = {},
setters,
attrs;
for (var i = names.length; i--;) {
node = meta[names[i]];
layers[names[i]] = core.getValidAttributeNames(node)
.map(attr => prepAttribute(core, node, attr))
attrs = core.getValidAttributeNames(node)
.map(attr => prepAttribute(core, node, attr));
layers[names[i]] = {};
layers[names[i]].args = attrs
.filter(isArgument)
.sort(sortByIndex);
layers[names[i]].setters = {};
setters = attrs.filter(isSetter);
for (var j = setters.length; j--;) {
layers[names[i]].setters[setters[j].name] = setters[j];
}
}
return layers;
+591 -282
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-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:
+1
Ver Arquivo
@@ -2687,6 +2687,7 @@ function LuaContext(){
}
exports.stdlib(_G, helpers)();
}
this.__helpers = helpers;
}
LuaContext.prototype = {}
+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;
+8
Ver Arquivo
@@ -18,3 +18,11 @@
.deepforge-logo .item-label {
font-family: 'Audiowide', cursive;
}
.create-node text {
font-style: italic;
}
.job-canceled {
background-color: #ffe0b2;
}
-19
Ver Arquivo
@@ -1,19 +0,0 @@
.new-node-decorator rect {
fill: #78909C;
/*fill: #90caf9;*/
}
.new-node-decorator circle {
fill: #81c784;
/*fill: #90caf9;*/
}
.new-node-decorator line {
stroke: white;
stroke-width: 4px;
}
.new-node-decorator .dark line {
stroke: black;
stroke-width: 2.5px;
}
-84
Ver Arquivo
@@ -1,84 +0,0 @@
/* globals define */
// This contains decorators for actions such as 'New Operation' so
// the given action can be used as a node in NodePrompter, etc
define([
'css!./AddDecorator.css'
], function(
) {
var NewDecorator = function (opts) {
this.$el = opts.parentEl.append('g')
.attr('class', 'centering-offset');
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.radius = opts.radius || 20;
this.height = this.radius*2;
this.width = opts.width || 90;
this.size = this.radius * 1.00;
if (opts.circle) {
this.render = this.renderCircle;
} else {
this.render = this.renderRect;
}
};
NewDecorator.prototype.renderRect = function() {
this.$body.remove();
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.$body.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', this.width)
.attr('height', this.height);
this.renderPlus()
.attr('class', 'dark')
.attr('transform', `translate(${this.width/2-this.size}, 0)`);
};
NewDecorator.prototype.renderCircle = function() {
this.$body.remove();
this.$body = this.$el.append('g')
.attr('class', 'new-node-decorator');
this.$body.append('circle')
.attr('cx', this.radius)
.attr('cy', this.radius)
.attr('r', this.radius);
this.renderPlus();
this.$el.attr('transform', `translate(${this.width/2-this.size}, ${this.height/2-this.size})`);
};
NewDecorator.prototype.renderPlus = function() {
// Create a large '+' symbol in a rectangle
var start = this.radius-this.size/2,
end = start + this.size,
middle = (start+end)/2,
plus = this.$body.append('g');
plus.append('line')
.attr('x1', start)
.attr('x2', end)
.attr('y1', middle)
.attr('y2', middle)
.attr('stroke', 'black');
plus.append('line')
.attr('x1', middle)
.attr('x2', middle)
.attr('y1', start)
.attr('y2', end)
.attr('stroke', 'black');
return plus;
};
return NewDecorator;
});
+65
Ver Arquivo
@@ -0,0 +1,65 @@
/*globals define, WebGMEGlobal*/
define([
'widgets/EasyDAG/Buttons',
'widgets/EasyDAG/Icons'
], function(
EasyDAGButtons,
Icons
) {
// Create a GoToBase button
var client = WebGMEGlobal.Client;
var GoToBase = function(params) {
// Check if it should be disabled
var baseId = this._getBaseId(params.item),
base = baseId && client.getNode(baseId);
if (!params.disabled) {
params.disabled = base ? base.isLibraryElement() : true;
}
EasyDAGButtons.ButtonBase.call(this, params);
};
GoToBase.SIZE = 10;
GoToBase.BORDER = 1;
GoToBase.prototype.BTN_CLASS = 'go-to-base';
GoToBase.prototype = new EasyDAGButtons.ButtonBase();
GoToBase.prototype._render = function() {
var lineRadius = GoToBase.SIZE - GoToBase.BORDER,
btnColor = '#90caf9';
if (this.disabled) {
btnColor = '#e0e0e0';
}
this.$el
.append('circle')
.attr('r', GoToBase.SIZE)
.attr('fill', btnColor);
// Show the 'code' icon
Icons.addIcon('code', this.$el, {
radius: lineRadius
});
};
GoToBase.prototype._onClick = function(item) {
var node = client.getNode(item.id),
baseId = node.getBaseId();
WebGMEGlobal.State.registerActiveObject(baseId);
};
GoToBase.prototype._getBaseId = function(item) {
var n = client.getNode(item.id);
return n && n.getBaseId();
};
return {
DeleteOne: EasyDAGButtons.DeleteOne,
GoToBase: GoToBase
};
});
+2 -2
Ver Arquivo
@@ -7,9 +7,9 @@ define([
var OperationControl = function() {
};
OperationControl.prototype.hasMetaName = function(id, name) {
OperationControl.prototype.hasMetaName = function(id, name, inclusive) {
var node = this._client.getNode(id),
bId = node.getBaseId(),
bId = inclusive ? id : node.getBaseId(),
baseName;
while (bId) {
+5
Ver Arquivo
@@ -3,11 +3,13 @@
define([
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/OperationControl',
'deepforge/Constants',
'widgets/EasyDAG/AddNodeDialog',
'underscore'
], function(
EasyDAGControl,
OperationControl,
CONSTANTS,
AddNodeDialog,
_
) {
@@ -72,6 +74,8 @@ define([
var desc = EasyDAGControl.prototype._getObjectDescriptor.call(this, id),
node = this._client.getNode(id);
desc.inputs = [];
desc.outputs = [];
if (this.hasMetaName(id, 'Operation')) {
// Only decorate operations in the currently active node
if (this._currentNodeId !== desc.parentId) {
@@ -95,6 +99,7 @@ define([
// Remove the 'code' attribute
if (desc.attributes.code) {
delete desc.attributes[CONSTANTS.LINE_OFFSET];
delete desc.attributes.code;
}
+60
Ver Arquivo
@@ -0,0 +1,60 @@
/*globals define*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'underscore'
], function(
PanelBaseWithHeader,
IActivePanel,
_
) {
var RenameablePanel = function() {
PanelBaseWithHeader.apply(this, arguments);
};
_.extend(
RenameablePanel.prototype,
PanelBaseWithHeader.prototype,
IActivePanel.prototype
);
RenameablePanel.OPTIONS = PanelBaseWithHeader.OPTIONS;
RenameablePanel.prototype.initializeRenameable = function () {
this.$panelHeaderTitle.on('dblclick', this.editTitle.bind(this));
};
RenameablePanel.prototype.currentNodeId = function () {
return this.control._currentNodeId;
};
RenameablePanel.prototype.currentBaseName = function () {
var currentId = this.currentNodeId(),
node = this._client.getNode(currentId),
baseId = node.getBaseId(),
base = this._client.getNode(baseId);
return base.getAttribute('name');
};
RenameablePanel.prototype.editTitle = function () {
this.$panelHeaderTitle.editInPlace({
css: {
'z-index': 1000
},
onChange: (oldValue, newValue) => {
var nodeId = this.currentNodeId(),
type = this.currentBaseName(),
msg = `Renamed ${type}: ${oldValue} -> ${newValue}`;
if (!/^\s*$/.test(newValue)) {
this._client.startTransaction(msg);
this._client.setAttributes(nodeId, 'name', newValue);
this._client.completeTransaction();
}
}
});
};
return RenameablePanel;
});
+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'
}
});
@@ -53,7 +53,17 @@ define([
ArtifactOpDecorator.prototype.savePointer = function(name, to) {
// When the 'artifact' pointer is changed, we should change the base
// of the data output node to the target type
if (name === this.castOpts.ptr && (typeof to === 'string')) {
if (typeof to !== 'string') {
var outputId = this._node.outputs[0] && this._node.outputs[0].id;
// Clear the data handle of the output
this.client.startTransaction(`Removing output of ${this.name}`);
this.client.delPointer(this._node.id, name);
if (outputId) {
this.client.delAttributes(outputId, 'data');
}
this.client.completeTransaction();
} else if (name === this.castOpts.ptr) { // set the casted value
this.client.startTransaction(`Setting output of ${this.name} to ${to}`);
this.castOutputType(to);
this.client.makePointer(this._node.id, name, to);
@@ -1,10 +1,6 @@
/*globals define, _*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'css!./JobDecorator.EasyDAGWidget.css'
@@ -20,6 +16,7 @@ define([
pending: '#9e9e9e',
queued: '#cfd8dc',
running: '#fff59d',
canceled: '#ffcc80',
success: '#66bb6a',
fail: '#e57373'
};
@@ -35,6 +32,8 @@ define([
status: true,
execFiles: true,
stdout: true,
secret: true,
jobId: true,
debug: true
};
EllipseDecorator.call(this, options);
@@ -0,0 +1,16 @@
/* globals define, _*/
define([
'decorators/EllipseDecorator/EasyDAG/AttributeField'
], function(
AttributeFieldBase
) {
// Attribute field in which the label is clickable and the attribute meta is editable
var AttributeField = function() {
AttributeFieldBase.apply(this, arguments);
this.$label.on('click', () => this.onLabelClick());
};
_.extend(AttributeField.prototype, AttributeFieldBase.prototype);
return AttributeField;
});
@@ -0,0 +1,26 @@
/* globals define */
define([
], function(
) {
var CreateAttrField = function(logger, pEl, y) {
this.$el = pEl.append('text')
.attr('y', y)
.attr('class', 'create-attr-field')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.attr('font-weight', 'bold')
.attr('font-style', 'italic')
.text('New Attribute')
.on('click', () => this.onClick());
};
CreateAttrField.prototype.render =
CreateAttrField.prototype.destroy = function() {};
CreateAttrField.prototype.width = function() {
return this.$el[0][0].getBoundingClientRect().width;
};
return CreateAttrField;
});
@@ -1,15 +1,17 @@
/*globals define, $,_*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'./AttributeField',
'./CreateAttributeField',
'decorators/MetaDecorator/DiagramDesigner/AttributeDetailsDialog',
'css!./OpIntDecorator.EasyDAGWidget.css'
], function (
DecoratorBase
DecoratorBase,
AttributeField,
CreateAttributeField,
AttributeDetailsDialog
) {
'use strict';
@@ -17,13 +19,7 @@ define([
var OpIntDecorator,
DECORATOR_ID = 'OpIntDecorator';
// OpInt nodes need to be able to...
// - show their ports
// - highlight ports
// - unhighlight ports
// - report the location of specific ports
OpIntDecorator = function (options) {
this.color = this.color || '#78909c';
DecoratorBase.call(this, options);
};
@@ -31,9 +27,9 @@ define([
OpIntDecorator.prototype.DECORATOR_ID = DECORATOR_ID;
OpIntDecorator.prototype.initialize = function() {
if (this._node.baseName === 'Operation') {
if (this.isOperation()) {
this.color = '#2196f3';
} else {
} else if (this._node.baseName) {
// On hover, show the type
this.enableTooltip(this._node.baseName, 'dark');
}
@@ -41,6 +37,109 @@ define([
this.$name.on('dblclick', this.editName.bind(this));
};
OpIntDecorator.prototype.AttributeField = AttributeField;
OpIntDecorator.prototype.isOperation = function() {
return this._node.baseName === 'Operation';
};
OpIntDecorator.prototype.createAttributeFields = function(y, width) {
var field,
initialY = y;
if (!this.isOperation()) {
return y;
}
y = DecoratorBase.prototype.createAttributeFields.call(this, y, width);
// Change attribute field so clicking allows user to edit/delete the field
this.fields.forEach(field =>
field.onLabelClick = this.editAttributeMeta.bind(this, field.name));
// Add the 'create new attribute' field
y += this.ROW_HEIGHT + (y === initialY ? 0 : 10);
field = new CreateAttributeField(this.logger, this.$attributes, y, width);
field.onClick = this.newAttribute.bind(this);
this.fields.push(field);
return y;
};
OpIntDecorator.prototype.newAttribute = function() {
var defSchema = {
type: 'string'
};
this.editAttributeMeta(null, defSchema);
};
OpIntDecorator.prototype.expand = function() {
DecoratorBase.prototype.expand.call(this, this.isOperation());
};
OpIntDecorator.prototype.editAttributeMeta = function(name, defSchema) {
var dialog = new AttributeDetailsDialog(),
node = this.client.getNode(this._node.id),
attrNames = node.getValidAttributeNames(),
attrInfo = this._node.attributes[name] || defSchema,
schema,
i;
// Open the dialog for editing the attribute
schema = _.extend({defaultValue: attrInfo.value}, attrInfo);
// Remove the current name
i = attrNames.indexOf(name);
if (i !== -1) {
attrNames.splice(i, 1);
}
dialog.show(schema, attrNames,
desc => this.setAttributeMeta(name, desc),
() => this.deleteAttribute(name));
};
OpIntDecorator.prototype.deleteAttribute = function(name) {
var opName = this._node.attributes.name.value,
msg = `Deleting "${name}" attribute from "${opName}" operation`;
this.client.startTransaction(msg);
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
this.client.completeTransaction();
};
OpIntDecorator.prototype.setAttributeMeta = function(name, desc) {
var schema,
opName = this._node.attributes.name.value,
msg = `Updating "${name}" attribute in "${opName}" operation`;
// Create the schema from the desc
schema = {
type: desc.type,
min: desc.min,
max: desc.max,
regexp: desc.regexp
};
if (desc.isEnum) {
schema.enum = desc.enumValues;
}
// Update the operation's attribute
this.client.startTransaction(msg);
if (name !== desc.name) { // Renaming attribute
if (name) {
this.client.removeAttributeSchema(this._node.id, name);
this.client.delAttributes(this._node.id, name);
}
name = desc.name;
}
this.client.setAttributeSchema(this._node.id, name, schema);
this.client.setAttributes(this._node.id, name, desc.defaultValue);
this.client.completeTransaction();
};
OpIntDecorator.prototype.editName = function() {
var html = this.$name[0][0],
position = html.getBoundingClientRect(),
@@ -90,8 +189,5 @@ define([
return this._node.name;
};
// clicking on the name should allow the user to edit it in place
// TODO
return OpIntDecorator;
});
@@ -1,10 +1,6 @@
/*globals define, _, Opentip*/
/*jshint browser: true, camelcase: false*/
/**
* @author brollb / https://github.com/brollb
*/
define([
'decorators/EllipseDecorator/EasyDAG/EllipseDecorator.EasyDAGWidget',
'css!./OperationDecorator.EasyDAGWidget.css'
@@ -47,29 +43,22 @@ define([
};
OperationDecorator.prototype.condense = function() {
var path,
width,
rx;
width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
rx = width/2;
path = [
`M${-rx},0`,
`l ${width} 0`,
`l 0 ${this.dense.height}`,
`l -${width} 0`,
`l 0 -${this.dense.height}`
].join(' ');
var width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
this.$body
.attr('d', path);
.transition()
.attr('x', -width/2)
.attr('y', 0)
.attr('width', width)
.attr('height', this.dense.height);
// Clear the attributes
this.$attributes.remove();
this.clearFields();
this.$attributes = this.$el.append('g')
.attr('fill', '#222222');
.attr('fill', 'none');
this.createAttributeFields(0, width);
this.createPointerFields(0, width, true);
this.height = this.dense.height;
this.width = width;
+8 -5
Ver Arquivo
@@ -105,7 +105,7 @@ define([
return this.getUniqueExecName(name + '_execution');
})
.then(execName => {
var isSnapshot = this.getCurrentConfig().snapshot;
var isSnapshot = !this.getCurrentConfig().debug;
this.logger.debug(`Creating execution ${execName}`);
@@ -118,7 +118,7 @@ define([
this.core.addMember(this.activeNode, 'executions', tgtNode);
return this.project.createTag(
execName.replace(/ /g, '_'),
execName,
this.currentHash
);
})
@@ -153,10 +153,13 @@ define([
};
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 => {
@@ -181,7 +184,7 @@ define([
};
CreateExecution.prototype.copyOperations = function (nodes, dst) {
var snapshot = this.getCurrentConfig().snapshot;
var snapshot = !this.getCurrentConfig().debug;
if (snapshot) {
return Q.all(nodes.map(node => {
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
{
"id": "CreateExecution",
"name": "CreateExecution",
"name": "Create Execution",
"version": "0.1.0",
"description": "",
"icon": {
+62 -44
Ver Arquivo
@@ -1,28 +1,18 @@
/*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',
'js/RegistryKeys',
'js/Constants',
'js/Panels/MetaEditor/MetaEditorConstants',
'underscore',
'text!deepforge/layers.json',
'text!./metadata.json'
], function (
PluginConfig,
PluginBase,
yaml,
generateGuid,
REGISTRY_KEYS,
CONSTANTS,
META_CONSTANTS,
_,
DEFAULT_LAYERS,
@@ -66,7 +56,7 @@ define([
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
@@ -86,8 +76,7 @@ define([
layers;
try {
layers = JSON.parse(text)
.filter(layer => layer.type !== 'Criterion');
layers = JSON.parse(text);
} catch (e) {
return callback('JSON parse error: ' + e, this.result);
}
@@ -131,7 +120,7 @@ define([
newLayers
.map(name => this.META[name])
.filter(layer => !!layer)
.forEach(layer => this.core.setPointer(layer, 'base', this.META.Layer));
.forEach(layer => this.core.setBase(layer, this.META.Layer));
oldLayers = Object.keys(this.META)
.filter(name => name !== 'Layer')
@@ -149,9 +138,9 @@ define([
categories.forEach(cat => {
content[cat]
.forEach(layer => {
var attrs = layer.params,
name = layer.name;
nodes[name] = this.createMetaNode(name, nodes[cat], cat, attrs);
var name = layer.name;
nodes[name] = this.createMetaNode(name, nodes[cat], cat, layer);
// Make the node non-abstract
this.core.setRegistry(nodes[name], 'isAbstract', false);
});
@@ -223,12 +212,25 @@ define([
}
};
CreateTorchMeta.prototype.createMetaNode = function (name, base, tabName, attrs) {
var isBoolean = txt => {
return typeof txt === 'boolean' || (txt === 'false' || txt === 'true');
};
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 = {},
attrs,
desc;
if (layer) {
attrs = layer.params;
setters = layer.setters;
defaults = layer.defaults;
}
if (!tabId) {
this.logger.error(`No meta sheet for ${tabName}`);
}
@@ -245,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
@@ -270,10 +272,12 @@ define([
if (attrs) { // Add the attributes
// Remove attributes not in the given list
var currentAttrs = this.core.getValidAttributeNames(node),
defVal,
rmAttrs;
rmAttrs = _.difference(currentAttrs, attrs) // old attribute names
.filter(attr => attr !== 'name');
.filter(attr => attr !== 'name')
.filter(attr => !setters[attr]);
if (rmAttrs.length) {
this.logger.debug(`Removing ${rmAttrs.join(', ')} from ${name}`);
@@ -286,10 +290,35 @@ define([
});
attrs.forEach((name, index) => {
var desc = {};
desc = {};
desc.argindex = index;
desc.default = '';
this.addAttribute(name, node, desc);
defVal = defaults.hasOwnProperty(name) ? defaults[name] : '';
this.addAttribute(name, node, desc, defVal);
});
// Add the setters to the meta
Object.keys(setters).forEach(name => {
var values;
desc = setters[name];
defVal = defaults.hasOwnProperty(name) ? defaults[name] : '';
if (desc.setterType === 'const') {
values = Object.keys(desc.setterFn);
desc.isEnum = true;
desc.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
defVal = values[0] === 'true' ? false : true;
}
if (isBoolean(defVal)) {
this.logger.debug(`setting ${name} to boolean`);
desc.type = 'boolean';
}
}
}
this.addAttribute(name, node, desc, defVal);
});
}
this.logger.debug(`added ${name} to the meta`);
@@ -324,41 +353,30 @@ define([
};
};
CreateTorchMeta.prototype.addAttribute = function (name, node, def) {
var initial,
schema = {};
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;
}
// Add the infer flag
if (def.infer) {
schema.infer = def.infer;
schema.max = +schema.max;
}
// Add the argindex flag
schema.argindex = def.argindex;
schema.argindex = schema.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;
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+14
Ver Arquivo
@@ -0,0 +1,14 @@
{
"id": "ExecuteJob",
"name": "ExecuteJob",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"writeAccessRequired": false,
"configStructure": []
}
@@ -0,0 +1,64 @@
-- Instantiate the deepforge object
deepforge = {}
function deepforge.id()
if __deepforge_id == nil then
__deepforge_id = 0
end
__deepforge_id = __deepforge_id + 1
return __deepforge_id
end
function deepforge._cmd(...)
local cmd = '<%= START_CMD %>'
local arg = {...}
local n = #arg
for i=1,n do
cmd = cmd .. ' ' .. tostring(arg[i])
end
print(cmd)
end
-- Graph support
Graph = torch.class('deepforge.Graph')
function Graph:__init(name)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE %>', self.id, name)
end
_Line = torch.class('deepforge._Line')
function _Line:__init(graphId, name, opts)
self.id = deepforge.id()
self.name = name
deepforge._cmd('<%= GRAPH_CREATE_LINE %>', graphId, self.id, name)
end
function _Line:add(x, y)
deepforge._cmd('<%= GRAPH_PLOT %>', self.id, x, y)
end
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,7 +1,10 @@
-- Instantiate the deepforge object
require './deepforge'
-- run the <%= name %> and serialize the results
print('\n############### Running "<%= name %>" Operation ############### ')
print('\n############### Running "<%= name.replace(/'/g, '\\\'') %>" Operation ############### ')
results = require './main'
print('############### "<%= name %>" Operation Complete! ###############')
print('############### "<%= name.replace(/'/g, '\\\'') %>" Operation Complete! ###############')
-- serialize by type
outputs = require './outputs'
@@ -1,22 +1,26 @@
/*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,
SERIALIZE,
DESERIALIZE
) {
var BASH = 'th init.lua 2>&1';
return {
BASH,
START,
ENTRY,
MAIN,
SERIALIZE,
DEEPFORGE,
DESERIALIZE
};
});
+125
Ver Arquivo
@@ -0,0 +1,125 @@
// 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'),
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',
protocol = url.split('://').shift(),
address,
port = (url.split(':') || ['80']).pop();
address = url.replace(protocol + '://', '')
.replace(':' + port, '');
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) {
console.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 => console.error(`${filename} upload failed: ${err}`));
});
};
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 getData = function(ipath, hash) {
// Download the data and put it in the given path
var deferred = Q.defer();
return blobClient.getObject(hash)
.then(buffer => fs.writeFile(ipath, buffer, (err, result) => {
if (err) {
console.error('Retrieving ' + ipath + ' failed!');
deferred.reject(err);
}
console.error('Retrieved ' + ipath);
deferred.resolve(err);
}));
};
// Download the large files
var inputData = JSON.parse(fs.readFileSync('./input-data.json')),
inputPaths = Object.keys(inputData);
// Request the data from the blob
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', data => process.stdout.write(data));
job.on('close', code => {
exitCode = code;
log('script finished w/ exit code:', code);
checkFinished();
});
});
});
+78 -589
Ver Arquivo
@@ -3,23 +3,19 @@
define([
'plugin/CreateExecution/CreateExecution/CreateExecution',
'deepforge/plugin/PtrCodeGen',
'plugin/ExecuteJob/ExecuteJob/ExecuteJob',
'common/storage/constants',
'common/core/constants',
'q',
'text!./metadata.json',
'./templates/index',
'deepforge/plugin/LocalExecutor',
'executor/ExecutorClient',
'underscore'
], function (
CreateExecution,
PtrCodeGen,
ExecuteJob,
STORAGE_CONSTANTS,
CONSTANTS,
Q,
pluginMetadata,
Templates,
LocalExecutor, // DeepForge operation primitives
ExecutorClient,
_
) {
'use strict';
@@ -32,8 +28,6 @@ define([
* @classdesc This class represents the plugin ExecutePipeline.
* @constructor
*/
var OUTPUT_INTERVAL = 1500,
STDOUT_FILE = 'job_stdout.txt';
var ExecutePipeline = function () {
// Call base class' constructor.
CreateExecution.call(this);
@@ -49,12 +43,13 @@ define([
* @type {object}
*/
ExecutePipeline.metadata = pluginMetadata;
ExecutePipeline.UPDATE_INTERVAL = 1500;
// Prototypical inheritance from CreateExecution.
ExecutePipeline.prototype = Object.create(CreateExecution.prototype);
ExecutePipeline.prototype.constructor = ExecutePipeline;
_.extend(ExecutePipeline.prototype, ExecuteJob.prototype);
ExecutePipeline.prototype.initRun = function () {
// Cache
this.nodes = {};
@@ -79,7 +74,14 @@ 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
this._metadata = {};
this._markForDeletion = {}; // id -> node
this._oldMetadataByName = {}; // name -> id
this.lastAppliedCmd = {};
};
/**
@@ -103,19 +105,19 @@ define([
startPromise = this.createExecution(this.activeNode)
.then(execNode => {
this.activeNode = execNode;
return this.core.loadSubTree(this.activeNode);
});
} else if (this.core.isTypeOf(this.activeNode, this.META.Execution)) {
startPromise = this.core.loadSubTree(this.activeNode);
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(subtree => {
startPromise
.then(() => this.core.loadSubTree(this.activeNode))
.then(subtree => {
var children = subtree
.filter(n => this.core.getParent(n) === this.activeNode);
@@ -134,7 +136,16 @@ define([
// When 'save' is called, it should still finish any current save op
// before continuing
this._currentSave = this._currentSave
.then(() => CreateExecution.prototype.save.call(this, msg));
.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);
}
});
return this._currentSave;
};
@@ -156,7 +167,10 @@ define([
// Set the status for each job to 'pending'
nodes.filter(node => this.core.isTypeOf(node, this.META.Job))
.forEach(node => this.core.setAttribute(node, 'status', 'pending'));
.forEach(node => {
this.recordOldMetadata(node);
this.core.setAttribute(node, 'status', 'pending');
});
// Set the status of the execution to 'running'
this.core.setAttribute(this.activeNode, 'status', 'running');
@@ -186,9 +200,7 @@ define([
this.completedCount = 0;
// Get all connections
conns = nodes.filter(node =>
this.core.getPointerPath(node, 'src') && this.core.getPointerPath(node, 'dst')
);
conns = this.getConnections(nodes);
// Get all operations
nodes
@@ -251,8 +263,28 @@ define([
this.executeReadyOperations();
};
ExecutePipeline.prototype.onOperationFail = function(node, err) {
var job = this.core.getParent(node),
id = this.core.getPath(node),
name = this.core.getAttribute(node, 'name');
this.logger.debug(`Operation ${name} (${id}) failed: ${err}`);
this.core.setAttribute(job, 'status', 'fail');
this.clearOldMetadata(job);
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--;
@@ -260,17 +292,33 @@ 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, '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);
@@ -287,7 +335,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();
}
@@ -298,276 +346,16 @@ define([
readyOps.forEach(jobId => {
delete this.incomingCounts[jobId];
});
this.logger.info(`Found ${readyOps.length} ready job(s)`);
readyOps.reduce((prev, jobId) => {
return prev.then(() => this.executeOperation(jobId));
return prev.then(() => this.executeJob(this.nodes[jobId]));
}, Q());
this.runningJobs += readyOps.length;
this.logger.info(`There are now ${this.runningJobs} running jobs`);
this.logger.info(`There ${this.runningJobs === 1 ? 'is' : 'are'} now ${this.runningJobs} running job(s)`);
return readyOps.length;
};
ExecutePipeline.prototype.getOperation = function (jobId) {
var node = this.nodes[jobId],
children = this.core.getChildrenPaths(node).map(id => this.nodes[id]);
// Currently, jobs
return children.find(child => this.isMetaTypeOf(child, this.META.Operation));
};
ExecutePipeline.prototype.executeOperation = function (jobId) {
var node = this.getOperation(jobId),
name = this.core.getAttribute(node, 'name'),
localTypeId = this.getLocalOperationType(node),
artifact,
artifactName,
files,
data = {},
inputs;
// Execute any special operation types here - not on an executor
this.logger.debug(`Executing operation "${name}"`);
if (localTypeId !== null) {
return this.executeLocalOperation(localTypeId, node);
} else {
// Generate all execution files
return this.createOperationFiles(node).then(results => {
this.logger.info('Created operation files!');
files = results;
artifactName = `${name}_${jobId.replace(/\//g, '_')}-execution-files`;
artifact = this.blobClient.createArtifact(artifactName);
// Add the input assets
// - get the metadata (name)
// - add the given inputs
inputs = Object.keys(files.inputAssets);
return Q.all(
inputs.map(input => { // Get the metadata for each input
var hash = files.inputAssets[input];
// data asset for "input"
return this.blobClient.getMetadata(hash);
})
);
})
.then(mds => {
// get (input, filename) tuples
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;
});
delete files.inputAssets;
// 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,
file;
outputs = outputArgs.map(pair => pair[0])
.map(name => {
return {
name: name,
resultPatterns: [`outputs/${name}`]
};
});
outputs.push({
name: 'stdout',
resultPatterns: [STDOUT_FILE]
});
if (this.debug) {
outputs.push({
name: name + '-all-files',
resultPatterns: []
});
}
config = {
cmd: 'bash',
args: ['run.sh'],
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
for (file in data) {
if (!data[file]) {
this.logger.warn(`Empty data hash has been found for file "${file}". Removing it...`);
delete data[file];
}
}
return artifact.addObjectHashes(data);
})
.then(() => {
this.logger.info(`Added ptr/input data hashes for "${artifactName}"`);
return artifact.addFiles(files);
})
.then(() => {
this.logger.info(`Added execution files for "${artifactName}"`);
return artifact.save();
})
.then(hash => {
this.logger.info(`Saved execution files "${artifactName}"`);
this.result.addArtifact(hash); // Probably only need this for debugging...
this.executeDistOperation(jobId, node, hash);
})
.fail(e => {
this.core.setAttribute(this.nodes[jobId], 'status', 'fail');
this.logger.info(`Setting ${jobId} status to "fail"`);
this.onPipelineComplete(`Distributed operation "${name}" failed ${e}`);
});
}
};
ExecutePipeline.prototype.executeDistOperation = function (jobId, opNode, hash) {
var name = this.core.getAttribute(opNode, 'name'),
opId = this.core.getPath(opNode),
executor = new ExecutorClient({
logger: this.logger,
serverPort: this.gmeConfig.server.port
});
this.logger.info(`Executing operation "${name}"`);
this.outputLineCount[jobId] = 0;
// Set the job status to 'running'
this.core.setAttribute(this.nodes[jobId], 'status', 'queued');
this.core.setAttribute(this.nodes[jobId], 'stdout', '');
this.logger.info(`Setting ${jobId} status to "queued" (${this.currentHash})`);
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, opId, jobId))
.catch(err => this.logger.error(`Could not execute "${name}": ${err}`));
};
ExecutePipeline.prototype.watchOperation = function (executor, hash, opId, jobId) {
var job = this.nodes[jobId],
info,
name;
return executor.getInfo(hash)
.then(_info => { // Update the job's stdout
var actualLine, // on executing job
currentLine = this.outputLineCount[jobId];
info = _info;
actualLine = info.outputNumber;
if (actualLine !== null && actualLine >= currentLine) {
this.outputLineCount[jobId] = actualLine + 1;
return executor.getOutput(hash, currentLine, actualLine+1)
.then(outputLines => {
var stdout = this.core.getAttribute(job, 'stdout'),
output = outputLines.map(o => o.output).join(''),
jobName = this.core.getAttribute(job, 'name');
// Handle the \b
// TODO
stdout += output;
this.core.setAttribute(job, 'stdout', stdout);
return this.save(`Received stdout for ${jobName}`);
});
}
})
.then(() => {
if (info.status === 'CREATED' || info.status === 'RUNNING') {
if (info.status === 'RUNNING' &&
this.core.getAttribute(this.nodes[jobId], 'status') !== 'running') {
name = this.core.getAttribute(this.nodes[jobId], 'name');
this.core.setAttribute(this.nodes[jobId], 'status', 'running');
this.save(`Started "${name}" operation in ${this.pipelineName}`);
}
setTimeout(
this.watchOperation.bind(this, executor, hash, opId, jobId),
ExecutePipeline.UPDATE_INTERVAL
);
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 => {
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.core.setAttribute(this.nodes[jobId], 'status', 'fail');
this.logger.info(`Setting ${jobId} status to "fail"`);
this.onPipelineComplete(`Operation "${opId}" failed! ${JSON.stringify(info)}`); // Failed
} else {
if (this.debug) {
this.result.addArtifact(info.resultHashes[name + '-all-files']);
}
this.onDistOperationComplete(opId, info);
}
});
})
.catch(err => this.logger.error(`Could not get op info for ${opId}: ${err}`));
};
ExecutePipeline.prototype.onDistOperationComplete = function (nodeId, result) {
var node = this.nodes[nodeId],
outputMap = {},
outputs;
// Match the output names to the actual nodes
// Create an array of [name, node]
// For now, just match by type. Later we may use ports for input/outputs
// Store the results in the outgoing ports
this.getOutputs(node)
.then(outputPorts => {
outputs = outputPorts.map(tuple => [tuple[0], tuple[2]]);
outputs.forEach(output => outputMap[output[0]] = output[1]);
// this should not be in directories -> flatten the data!
return Q.all(outputs.map(tuple => // [ name, node ]
this.blobClient.getArtifact(result.resultHashes[tuple[0]])
));
})
.then(artifacts => {
this.logger.info(`preparing outputs -> retrieved ${artifacts.length} objects`);
// Create new metadata for each
artifacts.forEach((artifact, i) => {
var name = outputs[i][0],
hash = artifact.descriptor.content[`outputs/${name}`].content;
this.core.setAttribute(outputMap[name], 'data', hash);
this.logger.info(`Setting ${nodeId} data to ${hash}`);
});
return this.onOperationComplete(node);
})
.fail(e => this.onPipelineComplete(`Operation ${nodeId} failed: ${e}`));
};
ExecutePipeline.prototype.onOperationComplete = function (opNode) {
var name = this.core.getAttribute(opNode, 'name'),
nextPortIds = this.getOperationOutputIds(opNode),
@@ -577,6 +365,7 @@ define([
hasReadyOps;
// Set the operation to 'success'!
this.clearOldMetadata(jNode);
this.runningJobs--;
this.core.setAttribute(jNode, 'status', 'success');
this.logger.info(`Setting ${jobId} status to "success"`);
@@ -634,305 +423,5 @@ define([
return this.getOperationOutputIds(node).map(id => this.nodes[id]);
};
//////////////////////////// Operation File/Dir Creators ////////////////////////////
ExecutePipeline.prototype.createOperationFiles = function (node) {
var files = {};
// For each operation, generate the output files:
// inputs/<arg-name>/init.lua (respective data deserializer)
// pointers/<name>/init.lua (result of running the main plugin on pointer target - may need a rename)
// outputs/<name>/ (make dirs for each of the outputs)
// outputs/init.lua (serializers for data outputs)
//
// attributes.lua (returns lua table of operation attributes)
// init.lua (main file -> calls main and serializes outputs)
// <name>.lua (entry point -> calls main operation code)
// add the given files
this.logger.info('About to create dist execution files');
return this.createEntryFile(node, files)
.then(() => this.createClasses(node, files))
.then(() => this.createCustomLayers(node, files))
.then(() => this.createInputs(node, files))
.then(() => this.createOutputs(node, files))
.then(() => this.createMainFile(node, files))
.then(() => {
this.createAttributeFile(node, files);
return Q.ninvoke(this, 'createPointers', node, files);
});
};
ExecutePipeline.prototype.createClasses = function (node, files) {
var isClass = {},
metaDict = this.core.getAllMetaNodes(this.rootNode),
metanodes,
classNodes,
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
// Get all the custom layers
metanodes.forEach(node => {
if (this.core.getAttribute(node, 'name') === 'Complex') {
isClass[this.core.getPath(node)] = true;
}
});
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base);
return isClass[baseId];
});
// Get the code definitions for each
code = classNodes.map(node =>
`require './${this.core.getAttribute(node, 'name')}.lua'`
).join('\n');
// Create the class files
classNodes.forEach(node => {
var name = this.core.getAttribute(node, 'name');
files[`classes/${name}.lua`] = this.core.getAttribute(node, 'code');
});
// Create the custom layers file
files['classes/init.lua'] = code;
};
ExecutePipeline.prototype.createCustomLayers = function (node, files) {
var isCustomLayer = {},
metaDict = this.core.getAllMetaNodes(this.rootNode),
metanodes,
customLayers,
code;
this.logger.info('Creating custom layer file...');
metanodes = Object.keys(metaDict).map(id => metaDict[id]);
// Get all the custom layers
metanodes.forEach(node => {
if (this.core.getAttribute(node, 'name') === 'CustomLayer') {
isCustomLayer[this.core.getPath(node)] = true;
}
});
customLayers = metanodes.filter(node =>
this.core.getMixinPaths(node).some(id => isCustomLayer[id]));
// Get the code definitions for each
code = 'require \'nn\'\n\n' + customLayers
.map(node => this.core.getAttribute(node, 'code')).join('\n');
// Create the custom layers file
files['custom-layers.lua'] = code;
};
ExecutePipeline.prototype.createInputs = function (node, files) {
var tplContents;
this.logger.info('Retrieving inputs and deserialize fns...');
return this.getInputs(node)
.then(inputs => {
// For each input, match the connection with the input name
// [ name, type ] => [ name, type, node ]
//
// For each input,
// - create the deserializer
// - put it in inputs/<name>/init.lua
// - copy the data asset to /inputs/<name>/init.lua
inputs = inputs
.filter(pair => !!this.core.getAttribute(pair[2], 'data')); // remove empty inputs
files.inputAssets = {}; // data assets
tplContents = inputs.map(pair => {
var name = pair[0],
node = pair[2],
deserFn = this.core.getAttribute(node, 'deserialize'),
base,
className;
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// (static) deserialize factory method
base = this.core.getBase(node);
className = this.core.getAttribute(base, 'name');
deserFn = `return ${className}.deserialize(path)`;
}
return {
name: name,
code: deserFn
};
});
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)));
})
.then(metadatas => {
// Create the deserializer
tplContents.forEach((ctnt, i) => {
// Get the name of the given asset
ctnt.filename = metadatas[i].name;
files['inputs/' + ctnt.name + '/init.lua'] = _.template(Templates.DESERIALIZE)(ctnt);
});
return files;
});
};
ExecutePipeline.prototype.createPointers = function (node, files, cb) {
var pointers,
nIds;
this.logger.info('Creating pointers file...');
pointers = this.core.getPointerNames(node)
.filter(name => name !== 'base')
.filter(id => this.core.getPointerPath(node, id) !== null);
nIds = pointers.map(p => this.core.getPointerPath(node, p));
files.ptrAssets = {};
Q.all(
nIds.map(nId => this.getPtrCodeHash(nId))
)
.then(resultHashes => {
var name = this.core.getAttribute(node, 'name');
this.logger.info(`Pointer generation for ${name} FINISHED!`);
resultHashes.forEach((hash, index) => {
files.ptrAssets[`pointers/${pointers[index]}/init.lua`] = hash;
});
return cb(null, files);
})
.fail(e => {
this.logger.error(`Could not generate pointer files for ${this.core.getAttribute(node, 'name')}: ${JSON.stringify(e)}`);
return cb(e);
});
};
ExecutePipeline.prototype.createOutputs = function (node, files) {
// For each of the output types, grab their serialization functions and
// create the `outputs/init.lua` file
this.logger.info('Creating outputs/init.lua...');
return this.getOutputs(node)
.then(outputs => {
var outputTypes = outputs
// Get the serialize functions for each
.map(tuple => {
var node = tuple[2],
serFn = this.core.getAttribute(node, 'serialize');
if (this.isMetaTypeOf(node, this.META.Complex)) {
// Complex objects are expected to define their own
// serialize methods
serFn = 'data:serialize(path)';
}
return [tuple[1], serFn];
});
files['outputs/init.lua'] = _.template(Templates.SERIALIZE)({types: outputTypes});
});
};
ExecutePipeline.prototype.getOutputs = function (node) {
return this.getOperationData(node, this.META.Outputs);
};
ExecutePipeline.prototype.getInputs = function (node) {
return this.getOperationData(node, this.META.Inputs);
};
ExecutePipeline.prototype.getOperationData = function (node, metaType) {
// Load the children and the output's children
return this.core.loadChildren(node)
.then(containers => {
var outputs = containers.find(c => this.core.isTypeOf(c, metaType));
return outputs ? this.core.loadChildren(outputs) : [];
})
.then(outputs => {
var bases = outputs.map(node => this.core.getMetaType(node));
// return [[arg1, Type1, node1], [arg2, Type2, node2]]
return outputs.map((node, i) => [
this.core.getAttribute(node, 'name'),
this.core.getAttribute(bases[i], 'name'),
node
]);
});
};
ExecutePipeline.prototype.createEntryFile = function (node, files) {
this.logger.info('Creating entry files...');
return this.getOutputs(node)
.then(outputs => {
var name = this.core.getAttribute(node, 'name'),
content = {};
// sort the outputs by the return values?
if (outputs.length > 1) {
this.logger.error('Multiple outputs not yet supported!');
}
// inputs and outputs
content.name = name;
content.outputs = outputs;
files['init.lua'] = _.template(Templates.ENTRY)(content);
});
};
ExecutePipeline.prototype.createMainFile = function (node, files) {
this.logger.info('Creating main file...');
return this.getInputs(node)
.then(inputs => {
var name = this.core.getAttribute(node, 'name'),
code = this.core.getAttribute(node, 'code'),
pointers = this.core.getPointerNames(node).filter(ptr => ptr !== 'base'),
content = {
name: name
};
// Get input data arguments
content.inputs = inputs
.map(pair => [pair[0], !this.core.getAttribute(pair[2], 'data')]); // remove empty inputs
// Defined variables for each pointers
content.pointers = pointers
.map(id => [id, this.core.getPointerPath(node, id) === null]);
// Add remaining code
content.code = code;
files['main.lua'] = _.template(Templates.MAIN)(content);
});
};
ExecutePipeline.prototype.createAttributeFile = function (node, files) {
var skip = ['outputs', 'inputs'],
table;
this.logger.info('Creating attributes file...');
table = '{\n\t' + this.core.getAttributeNames(node)
.filter(attr => skip.indexOf(attr) === -1)
.map(name => [name, JSON.stringify(this.core.getAttribute(node, name))])
.map(pair => pair.join(' = '))
.join(',\n\t') + '\n}';
files['attributes.lua'] = `-- attributes of ${this.core.getAttribute(node, 'name')}\nreturn ${table}`;
};
//////////////////////////// Special Operations ////////////////////////////
ExecutePipeline.prototype.executeLocalOperation = function (type, node) {
// Retrieve the given LOCAL_OP type
if (!this[type]) {
this.logger.error(`No local operation handler for ${type}`);
}
this.logger.info(`Running local operation ${type}`);
return this[type](node);
};
_.extend(
ExecutePipeline.prototype,
LocalExecutor.prototype,
PtrCodeGen.prototype
);
return ExecutePipeline;
});
+4 -12
Ver Arquivo
@@ -1,27 +1,19 @@
{
"id": "ExecutePipeline",
"name": "ExecutePipeline",
"name": "Execute Pipeline",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"class": "glyphicon glyphicon-random",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"disableBrowserSideExecution": true,
"configStructure": [
{
"name": "snapshot",
"displayName": "Snapshot",
"description": "Freeze the operation definitions and attributes at current value",
"value": true,
"valueType": "boolean",
"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,16 @@
/*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',
'underscore',
'text!./metadata.json'
], function (
PluginBase,
Constants,
createLayerDict,
dimensionality,
_,
metadata
) {
@@ -178,10 +172,35 @@ define([
};
GenerateArchitecture.prototype.createArgString = function (layer) {
return '(' + this.LayerDict[layer.name]
var setters = this.LayerDict[layer.name].setters,
setterNames = Object.keys(this.LayerDict[layer.name].setters),
base = layer[Constants.BASE],
desc,
fn,
layerCode;
layerCode = '(' + this.LayerDict[layer.name].args
.map(arg => layer[arg.name])
.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) {
fn = desc.setterFn;
layerCode += `:${fn}(${layer[setterNames[i]]})`;
}
}
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;
});
+2 -2
Ver Arquivo
@@ -1,11 +1,11 @@
{
"id": "GenerateArchitecture",
"name": "Generate Architecture",
"name": "Generate Torch Code",
"version": "0.1.0",
"description": "Generate torch architecture code",
"icon": {
"src": "",
"class": "glyphicon glyphicon-ok-circle"
"class": "glyphicon glyphicon-file"
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
@@ -0,0 +1,69 @@
/*globals define*/
/*jshint node:true, browser:true*/
define([
'text!./metadata.json',
'plugin/PluginBase'
], function (
pluginMetadata,
PluginBase
) {
'use strict';
pluginMetadata = JSON.parse(pluginMetadata);
/**
* Initializes a new instance of GenerateCriterion.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin GenerateCriterion.
* @constructor
*/
var GenerateCriterion = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
};
/**
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
* This is also available at the instance at this.pluginMetadata.
* @type {object}
*/
GenerateCriterion.metadata = pluginMetadata;
// Prototypical inheritance from PluginBase.
GenerateCriterion.prototype = Object.create(PluginBase.prototype);
GenerateCriterion.prototype.constructor = GenerateCriterion;
/**
* Main function for the plugin to execute. This will perform the execution.
* Notes:
* - Always log with the provided logger.[error,warning,info,debug].
* - Do NOT put any user interaction logic UI, etc. inside this method.
* - callback always has to be called even if error happened.
*
* @param {function(string, plugin.PluginResult)} callback - the result callback
*/
GenerateCriterion.prototype.main = function (callback) {
// Generate the code for the criterion layer and return a file
var name = this.core.getAttribute(this.activeNode, 'name'),
code = `require 'nn'\nreturn nn.${name}()`,
filename = `${name}.lua`;
// Using the logger.
this.logger.debug(`Generating code for ${name} criterion layer.`);
// Save the file
this.blobClient.putFile(filename, code)
.then(hash => {
this.result.setSuccess(true);
this.result.addArtifact(hash);
callback(null, this.result);
})
.catch(err => callback(err, this.result));
};
return GenerateCriterion;
});
+14
Ver Arquivo
@@ -0,0 +1,14 @@
{
"id": "GenerateCriterion",
"name": "Generate Criterion Code",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": false,
"writeAccessRequired": false,
"configStructure": []
}
+33 -21
Ver Arquivo
@@ -78,29 +78,32 @@ define([
}
// Get the base node
dataNode = this.core.createNode({
base: baseType,
parent: this.activeNode
});
this.core.setAttribute(dataNode, 'data', hash);
baseName = this.core.getAttribute(baseType, 'name');
var getName;
if (config.name) {
getName = Q().then(() => config.name);
} else {
getName = this.blobClient.getMetadata(hash)
.then(md => {
name = baseName[0].toLowerCase() + baseName.substring(1);
if (md) {
name = md.name.replace(/\.[^\.]*?$/, '');
}
return name;
this.getArtifactsDir()
.then(targetDir => {
dataNode = this.core.createNode({
base: baseType,
parent: targetDir
});
}
getName.then(name => this.core.setAttribute(dataNode, 'name', name))
this.core.setAttribute(dataNode, 'data', hash);
baseName = this.core.getAttribute(baseType, 'name');
var getName;
if (config.name) {
getName = Q().then(() => config.name);
} else {
getName = this.blobClient.getMetadata(hash)
.then(md => {
name = baseName[0].toLowerCase() + baseName.substring(1);
if (md) {
name = md.name.replace(/\.[^\.]*?$/, '');
}
return name;
});
}
return getName;
})
.then(name => this.core.setAttribute(dataNode, 'name', name))
.then(() => this.save(`Uploaded "${name}" data`))
.then(function () {
self.result.setSuccess(true);
@@ -112,5 +115,14 @@ define([
};
ImportArtifact.prototype.getArtifactsDir = function() {
// Find the artifacts dir
return this.core.loadChildren(this.rootNode)
.then(children => children
.find(child => this.core.getAttribute(child, 'name') === 'MyArtifacts') ||
this.activeNode
);
};
return ImportArtifact;
});
+2 -2
Ver Arquivo
@@ -1,10 +1,10 @@
{
"id": "ImportArtifact",
"name": "ImportArtifact",
"name": "Import Artifact",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"class": "glyphicon glyphicon-cloud-upload",
"src": ""
},
"disableServerSideExecution": false,
+13 -14
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,
@@ -57,12 +51,17 @@ define([
this.blobClient.getMetadata(srcHash)
.then(mdata => { // Create the new model
var name = mdata.name.replace('.lua', '');
this.tgtNode = this.core.createNode({
base: this.META.Architecture,
parent: this.activeNode
});
this.core.setAttribute(this.tgtNode, 'name', name);
// If the current node is an architecture, assume we are just extending it
this.importedName = mdata.name.replace('.lua', '');
if (this.isMetaTypeOf(this.activeNode, this.META.Architecture)) {
this.tgtNode = this.activeNode;
} else { // Create a new architecture
this.tgtNode = this.core.createNode({
base: this.META.Architecture,
parent: this.activeNode
});
this.core.setAttribute(this.tgtNode, 'name', this.importedName);
}
return this.blobClient.getObjectAsString(srcHash);
})
.then(src => { // Retrieved the source code
@@ -81,7 +80,7 @@ define([
return this.save('ImportTorch updated model.');
})
.then(() => { // changes saved successfully
var name = this.core.getAttribute(this.tgtNode, 'name');
var name = this.importedName;
this.result.setSuccess(true);
this.createMessage(this.tgtNode,
`Successfully imported ${name} architecture`);
@@ -96,7 +95,7 @@ define([
ImportTorch.prototype.loadNNMock = function () {
// This needs a refactor...
// createNN(this)
var lib = createNNSearcher(this).bind(this.context);
var lib = createNNSearcher(this, this.context).bind(this.context);
// Create a "searcher" to allow this 'nn' to be in the lib path
this.context._G.get('package').set('searchers', [function(name) {
+82 -4
Ver Arquivo
@@ -11,12 +11,23 @@ define([
) {
'use strict';
var createSearcher = function(plugin) {
var createSearcher = function(plugin, context) {
var core = plugin.core,
META = plugin.META,
logger = plugin.logger.fork('nn'),
parent = plugin.tgtNode,
LayerDict = createLayerDict(core, META);
LayerDict = createLayerDict(core, META),
helpers = context.__helpers,
oldSet = helpers.__set,
isSetting = false;
// Override the helper's '__set' method to detect
// if the code is in the middle of a "set".
helpers.__set = function() {
isSetting = true;
oldSet.apply(this, arguments);
isSetting = false;
};
var connect = function(src, dst) {
var conn = core.createNode({
@@ -76,6 +87,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
@@ -142,15 +160,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,
attrs = [].slice.call(arguments, 1),
ltGet = luajs.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);
@@ -165,6 +227,22 @@ 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);
if (!result && !isSetting) {
throw Error(`"${value}" is not supported for ${type}`);
}
return result;
};
return res;
};
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.
Arquivo binário não exibido.
+38 -38
Ver Arquivo
@@ -31,26 +31,8 @@
},
{
"id": "RootViz",
"title": "RootViz",
"panel": "panels/RootViz/RootVizPanel",
"DEBUG_ONLY": false
},
{
"id": "TilingViz",
"title": "TilingViz",
"panel": "panels/TilingViz/TilingVizPanel",
"DEBUG_ONLY": false
},
{
"id": "OperationCodeEditor",
"title": "OperationCodeEditor",
"panel": "panels/OperationCodeEditor/OperationCodeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "OperationInterfaceEditor",
"title": "OperationInterfaceEditor",
"panel": "panels/OperationInterfaceEditor/OperationInterfaceEditorPanel",
"title": "MainView",
"panel": "panels/MainView/MainViewPanel",
"DEBUG_ONLY": false
},
{
@@ -59,24 +41,6 @@
"panel": "panels/DataTypeEditor/DataTypeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "SerializeEditor",
"title": "SerializeEditor",
"panel": "panels/SerializeEditor/SerializeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "DeserializeEditor",
"title": "DeserializeEditor",
"panel": "panels/DeserializeEditor/DeserializeEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "Footer",
"title": "Footer",
"panel": "panels/Footer/FooterPanel",
"DEBUG_ONLY": false
},
{
"id": "LogViewer",
"title": "LogViewer",
@@ -100,5 +64,41 @@
"title": "ClassEditor",
"panel": "panels/ClassEditor/ClassEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "PipelineIndex",
"title": "PipelineIndex",
"panel": "panels/PipelineIndex/PipelineIndexPanel",
"DEBUG_ONLY": false
},
{
"id": "JobEditor",
"title": "JobEditor",
"panel": "panels/JobEditor/JobEditorPanel",
"DEBUG_ONLY": false
},
{
"id": "OutputViewer",
"title": "OutputViewer",
"panel": "panels/OutputViewer/OutputViewerPanel",
"DEBUG_ONLY": false
},
{
"id": "LineGraph",
"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
}
]
@@ -1,15 +1,14 @@
/*globals define */
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Tue May 17 2016 11:25:46 GMT-0400 (EDT).
*/
define([
'deepforge/globals',
'panels/EasyDAG/EasyDAGControl',
'js/NodePropertyNames',
'js/Utils/ComponentSettings',
'underscore'
], function (
DeepForge,
EasyDAGControl,
nodePropertyNames,
ComponentSettings,
@@ -43,6 +42,16 @@ define([
return 'ArchEditor';
};
ArchEditorControl.prototype.selectedObjectChanged = function(id) {
EasyDAGControl.prototype.selectedObjectChanged.call(this, id);
DeepForge.last.Architecture = id;
if (typeof id === 'string') {
var name = this._client.getNode(id).getAttribute('name');
this._widget.setTitle(name);
}
};
ArchEditorControl.prototype._getObjectDescriptor = function(id) {
var desc = EasyDAGControl.prototype._getObjectDescriptor.call(this, id);
@@ -55,7 +64,8 @@ define([
desc.attributes = {};
for (var i = names.length; i--;) {
schema = this._client.getAttributeSchema(id, names[i]);
if (names[i] === 'name' || schema.hasOwnProperty('argindex')) {
if (names[i] === 'name' || schema.hasOwnProperty('argindex') ||
schema.setterType) {
desc.attributes[names[i]] = allAttrs[names[i]];
}
}
@@ -84,6 +94,7 @@ define([
return desc;
};
////////////////////////// Layer Selection Logic //////////////////////////
ArchEditorControl.prototype._getValidInitialNodes = function() {
return this._client.getChildrenMeta(this._currentNodeId).items
// For now, anything is possible!
@@ -95,7 +106,67 @@ define([
return !this._client.getNode(nodeId).isAbstract();
})
.map(id => this._getObjectDescriptor(id))
.filter(obj => !obj.isConnection && obj.name !== 'Connection');
.filter(obj => !obj.isConnection && obj.name !== 'Connection')
.filter(layer => layer.layerType !== 'Criterion');
};
ArchEditorControl.prototype._getValidSuccessorNodes =
ArchEditorControl.prototype._getValidInitialNodes =
ArchEditorControl.prototype.getNonCriterionLayers = function() {
// Return all (non-criterion) layer types
var metanodes = this._client.getAllMetaNodes(),
layerId,
criterionId,
allLayerIds = [],
layers = [],
i;
for (i = metanodes.length; i--;) {
if (metanodes[i].getAttribute('name') === 'Layer') {
layerId = metanodes[i].getId();
break;
}
}
for (i = metanodes.length; i--;) {
if (layerId) {
if (!metanodes[i].isAbstract() &&
this._client.isTypeOf(metanodes[i].getId(), layerId)) {
if (metanodes[i].getAttribute('name') === 'Criterion') {
criterionId = metanodes[i].getId();
} else {
allLayerIds.push(metanodes[i].getId());
}
}
}
}
// Remove all criterion layers and abstract layers
for (i = allLayerIds.length; i--;) {
if (!this._client.isTypeOf(allLayerIds[i], criterionId)) {
layers.push({node: this._getObjectDescriptor(allLayerIds[i])});
}
}
return layers;
};
ArchEditorControl.prototype._isValidTerminalNode = function() {
return true;
};
// Widget extensions
ArchEditorControl.prototype._initWidgetEventHandlers = function() {
EasyDAGControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getCreateNewDecorator = this.getCreateNewDecorator.bind(this);
};
ArchEditorControl.prototype.getCreateNewDecorator = function() {
return this._client.decoratorManager.getDecoratorForWidget(
'EllipseDecorator',
'EasyDAG'
);
};
return ArchEditorControl;
@@ -5,13 +5,11 @@
*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'deepforge/viz/RenameablePanel',
'widgets/ArchEditor/ArchEditorWidget',
'./ArchEditorControl'
], function (
PanelBaseWithHeader,
IActivePanel,
RenameablePanel,
ArchEditorWidget,
ArchEditorControl
) {
@@ -22,11 +20,11 @@ define([
ArchEditorPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArchEditorPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
options[RenameablePanel.OPTIONS.LOGGER_INSTANCE_NAME] = 'ArchEditorPanel';
options[RenameablePanel.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
RenameablePanel.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
@@ -37,9 +35,7 @@ define([
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(ArchEditorPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(ArchEditorPanel.prototype, IActivePanel.prototype);
_.extend(ArchEditorPanel.prototype, RenameablePanel.prototype);
ArchEditorPanel.prototype._initialize = function () {
var self = this;
@@ -60,6 +56,7 @@ define([
widget: this.widget
});
this.initializeRenameable();
this.onActivate();
};
@@ -67,7 +64,7 @@ define([
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
ArchEditorPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
RenameablePanel.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
@@ -81,7 +78,7 @@ define([
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
RenameablePanel.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
@@ -3,10 +3,12 @@
define([
'panels/TextEditor/TextEditorControl',
'deepforge/lua',
'underscore',
'text!./DefaultCodeTemplate.ejs'
], function (
TextEditorControl,
lua,
_,
CODE_TEMPLATE
) {
@@ -29,7 +31,7 @@ define([
// input/output updates are actually activeNode updates
ClassCodeEditorControl.prototype._onUpdate = function (id) {
if (id === this._currentNodeId) {
TextEditorControl.prototype._onUpdate.call(this, this._currentNodeId);
TextEditorControl.prototype._onUpdate.call(this, id);
}
};
@@ -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;
});
@@ -2,9 +2,11 @@
/*jshint browser: true*/
define([
'panels/SerializeEditor/SerializeEditorControl',
'panels/TextEditor/TextEditorControl',
'underscore'
], function (
SerializeEditorControl,
TextEditorControl,
_
) {
@@ -20,15 +22,8 @@ define([
_.extend(
DeserializeEditorControl.prototype,
TextEditorControl.prototype
SerializeEditorControl.prototype
);
// input/output updates are actually activeNode updates
DeserializeEditorControl.prototype._onUpdate = function (id) {
if (id === this._currentNodeId) {
TextEditorControl.prototype._onUpdate.call(this, this._currentNodeId);
}
};
return DeserializeEditorControl;
});
@@ -0,0 +1,296 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants'
], function (
CONSTANTS
) {
'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._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] || [],
action = bool ? 'addNode' : 'removeNode';
// If removing, just get the ids
lines = bool ? lines : lines.map(line => line.id);
this._logger.info(`setting execution ${id} to ${bool ? 'displayed' : 'hidden'}`);
this.displayedExecutions[id] = bool;
// update the given lines
for (var i = lines.length; i--;) {
this._widget[action](lines[i]);
}
};
/* * * * * * * * Visualizer content update callbacks * * * * * * * */
ExecutionIndexControl.prototype.selectedObjectChanged = function (nodeId) {
var self = this;
self._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
if (self._currentNodeId) {
self._client.removeUI(self._territoryId);
}
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);
}
};
// 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];
this._logger.debug(`Looking up pipeline name for ${desc.name}: ${desc.pipelineName}`);
// 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(';')
.map(pair => {
var nums = pair.split(',').map(num => parseFloat(num));
return {
x: nums[0],
y: nums[1]
};
});
desc = {
id: id,
//execName: execName,
execId: execId,
lineName: node.getAttribute('name'),
name: node.getAttribute('name'),
type: 'line',
points: points
};
// Update records
if (!this._linesForExecution[execId]) {
this._linesForExecution[execId] = [];
}
this._linesForExecution[execId].push(desc);
this._lineToExec[id] = execId;
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];
if (execId) { // it is a line
delete this._lineToExec[id];
for (var k = this._linesForExecution[execId].length; k--;) {
if (this._linesForExecution[execId][k].id === id) {
this._linesForExecution[execId].splice(k, 1);
break;
}
}
}
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._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();
};
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;
});
+114 -77
Ver Arquivo
@@ -1,11 +1,13 @@
/*globals DeepForge, define, $, Materialize, WebGMEGlobal*/
/*globals DeepForge, 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
) {
@@ -68,58 +70,6 @@ define([
return null;
};
var UPLOAD_PLUGIN = 'ImportArtifact',
DATA_TYPE_CONFIG = {
name: 'dataTypeId',
displayName: 'Data Type Id',
valueType: 'string',
valueItems: []
};
var uploadArtifact = function() {
// Get the data types
var dataBase,
dataBaseId,
metanodes = this.client.getAllMetaNodes(),
dataTypes = []; // TODO
dataBase = metanodes.find(n => n.getAttribute('name') === 'Data');
if (!dataBase) {
this.logger.error('Could not find the base Data node!');
return;
}
dataBaseId = dataBase.getId();
dataTypes = metanodes.filter(n => this.client.isTypeOf(n.getId(), dataBaseId))
.map(node => node.getAttribute('name'));
this.logger.info(`Found ${dataTypes.length} data types`);
// Add the target type to the pluginMetadata... hacky :/
// FIXME: this should create it's own plugin dialog which allows
// users to select the data type
var metadata = WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN],
config = metadata.configStructure
.find(opt => opt.name === DATA_TYPE_CONFIG.name);
if (!config) {
config = DATA_TYPE_CONFIG;
WebGMEGlobal.allPluginsMetadata[UPLOAD_PLUGIN].configStructure.push(config);
}
config.valueItems = dataTypes;
config.value = dataTypes[0];
WebGMEGlobal.InterpreterManager.configureAndRun(metadata, (result) => {
if (!result) {
Materialize.toast('Artifact upload failed!', 2000);
return;
}
this.logger.info('Finished uploading ' + UPLOAD_PLUGIN);
Materialize.toast('Artifact upload complete!', 2000);
});
};
var importTorch = function() {
var pluginId = 'ImportTorch',
context = this.client.getCurrentPluginContext(pluginId),
@@ -144,20 +94,69 @@ define([
fileInput.click();
};
var returnToLastPipeline = () => {
var returnId = DeepForge.lastPipeline || DeepForge.places.MyPipelines;
var returnToLast = (place) => {
var returnId = DeepForge.last[place];
WebGMEGlobal.State.registerActiveObject(returnId);
};
return {
// Meta nodes
MyPipelines_META: [
var prototypeButtons = function(type, fromType) {
return [
{
name: 'Create new pipeline',
icon: 'queue',
action: DeepForge.create.Pipeline
name: `Return to ${fromType}`,
icon: 'input',
priority: 2,
color: 'teal',
filter: () => {
return DeepForge.last[fromType];
},
action: returnToLast.bind(null, fromType)
},
{
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),
name = node.getAttribute('name'),
msg = `Deleted ${type} Definition for "${name}"`;
this.deleteCurrentNode(msg);
setTimeout(() => Materialize.toast(msg, 2000), 10);
returnToLast(fromType);
}
}
],
];
};
var MyPipelinesButtons = [
{
name: 'Create new pipeline',
icon: 'queue',
action: DeepForge.create.Pipeline
}
];
var makeRestartButton = function(name, pluginId) {
return {
name: 'Restart ' + name,
icon: 'replay',
priority: 1000,
color: 'red',
filter: function() {
// Only show if stopped!
return !this.isRunning();
},
action: function(event) {
this.runExecutionPlugin(pluginId, event.shiftKey);
}
};
};
return {
HOME: MyPipelinesButtons,
MyPipelines_META: MyPipelinesButtons,
MyArchitectures_META: [
{
name: 'Create new architecture',
@@ -200,17 +199,16 @@ define([
{
name: 'Upload artifact',
icon: 'swap_vert',
action: uploadArtifact
}
],
Operation_META: [
{
name: 'Return to Pipeline',
icon: 'input',
action: returnToLastPipeline
action: DeepForge.create.Artifact
}
],
// Creating prototypes
Operation_META: prototypeButtons('Operation', 'Pipeline'),
Layer_META: prototypeButtons('Layer', 'Architecture'),
Complex_META: prototypeButtons('Class', 'Operation'),
Primitive_META: prototypeButtons('Primitive Type', 'Operation'),
// Instances
Data: [
{
@@ -220,10 +218,50 @@ define([
}
],
Job: [
makeRestartButton('Job', 'ExecuteJob'),
{
name: 'Download Execution Files',
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'),
// Stop execution button
{
name: 'Stop Running Execution',
icon: 'stop',
priority: 1001,
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();
}
}
],
Pipeline: [
@@ -234,14 +272,13 @@ define([
action: function() {
this.addOperation();
}
},
}
],
Architecture: [
{
name: 'Create new node',
icon: 'queue',
priority: 2,
action: function() {
this.addOperation();
}
name: 'Import Torch Architecture',
icon: 'swap_vert',
action: importTorch
}
]
};
@@ -1,13 +1,14 @@
/*globals DeepForge, $, define, _ */
/*globals DeepForge, $, WebGMEGlobal, window, define, _ */
/*jshint browser: true*/
define([
'panel/FloatingActionButton/styles/Materialize',
'blob/BlobClient',
'executor/ExecutorClient',
'js/Constants',
'panel/FloatingActionButton/FloatingActionButton',
'deepforge/viz/PipelineControl',
'deepforge/viz/NodePrompter',
'deepforge/viz/AddDecorator',
'./Actions',
'widgets/EasyDAG/AddNodeDialog',
'js/RegistryKeys',
@@ -16,12 +17,13 @@ define([
'text!./PluginConfig.json',
'deepforge/globals'
], function (
Materialize,
BlobClient,
ExecutorClient,
CONSTANTS,
PluginButton,
PipelineControl,
NodePrompter,
AddDecorator,
ACTIONS,
AddNodeDialog,
REGISTRY_KEYS,
@@ -35,6 +37,11 @@ define([
var ForgeActionButton= function (layoutManager, params) {
PluginButton.call(this, layoutManager, params);
this._pluginConfig = JSON.parse(PluginConfig);
this._executor = new ExecutorClient({
logger: this.logger.fork('ExecutorClient'),
serverPort: WebGMEGlobal.gmeConfig.server.port,
httpsecure: window.location.protocol === 'https:'
});
this._client = this.client;
this._actions = [];
this._blobClient = new BlobClient({
@@ -59,12 +66,19 @@ define([
actions,
basename;
if (!base) { // must be ROOT or FCO
basename = node.getAttribute('name') || 'ROOT_NODE';
actions = (ACTIONS[basename] || [])
.filter(action => !action.filter || action.filter.call(this));
return actions;
}
while (base && !(actions && actions.length)) {
basename = base.getAttribute('name') + suffix;
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));
}
}
@@ -183,8 +197,7 @@ define([
ForgeActionButton.prototype.promptLayerType = function() {
// Prompt for the new custom layer's base type
var deferred = Q.defer(),
metanodes = this.client.getAllMetaNodes(),
var metanodes = this.client.getAllMetaNodes(),
baseLayerId = metanodes.find(n => n.getAttribute('name') === 'Layer').getId(),
layerType,
types;
@@ -206,8 +219,7 @@ define([
};
});
AddNodeDialog.prompt(types, deferred.resolve);
return deferred.promise;
return AddNodeDialog.prompt(types);
};
ForgeActionButton.prototype.uploadFile = function(event) {
@@ -249,10 +261,7 @@ define([
/////////////// Expanding containers ///////////////
ForgeActionButton.prototype.addOperation = function() {
var ops = this.getValidInitialNodes(),
newOperation = {
id: NEW_OPERATION_ID,
Decorator: AddDecorator
};
newOperation = this.getNewOpNode();
// Add the 'New op button'
ops.push(newOperation);
@@ -260,15 +269,26 @@ define([
this.promptNode(ops, (selected, prompter) => {
if (selected.id === NEW_OPERATION_ID) {
prompter.destroy();
DeepForge.lastPipeline = this._currentNodeId;
DeepForge.create.Operation();
//WebGMEGlobal.State.registerActiveObject(newId);
} else {
this.createNode(selected.id);
}
});
};
ForgeActionButton.prototype.getNewOpNode = function() {
var Decorator = this.client.decoratorManager.getDecoratorForWidget(
'OperationDecorator', 'EasyDAG');
return {
id: NEW_OPERATION_ID,
class: 'create-node',
name: 'New Operation...',
Decorator: Decorator,
attributes: {}
};
};
ForgeActionButton.prototype.promptNode = function(nodes, selectFn) {
// Get the absolute location of the given button
var mainBtn = this.$el[0].children[0],
@@ -301,5 +321,83 @@ define([
return prompter.prompt(nodes, selectFn);
};
ForgeActionButton.prototype.deleteCurrentNode = function(msg) {
var nodeId = this._currentNodeId;
if (nodeId) {
this.client.startTransaction(msg);
this.client.delMoreNodes([nodeId]);
this.client.completeTransaction(msg);
}
};
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, 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);
});
};
ForgeActionButton.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;
};
ForgeActionButton.prototype.isRunningJob = function(job) {
var status = job.getAttribute('status');
return (status === 'running' || status === 'pending') &&
job.getAttribute('secret') && job.getAttribute('jobId');
};
ForgeActionButton.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 ForgeActionButton;
});
@@ -5,6 +5,7 @@
},
"ExecutePipeline": {
"icon": "play_arrow",
"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;
});
@@ -0,0 +1,118 @@
/*globals define, _ */
/*jshint browser: true*/
// This editor will be a split screen view w/ the operation code on the left
// and the terminal on the right.
//
// However, if the job is contained in a "snapshotted" execution, then it will
// be considered read only and only show the terminal output
define([
'panels/TilingViz/TilingVizPanel',
'panels/OutputViewer/OutputViewerPanel',
'panels/OperationCodeEditor/OperationCodeEditorPanel',
'js/Constants'
], function (
TilingViz,
OutputViewer,
OperationCodeEditor,
CONSTANTS
) {
'use strict';
var JobEditorPanel;
JobEditorPanel = function (layoutManager, params) {
TilingViz.call(this, layoutManager, params);
this.readOnly = false;
};
//inherit from PanelBaseWithHeader
_.extend(JobEditorPanel.prototype, TilingViz.prototype);
JobEditorPanel.prototype.getPanels = function () {
if (this.readOnly) {
return [OutputViewer];
} else {
return [OperationCodeEditor, OutputViewer];
}
};
JobEditorPanel.prototype.selectedObjectChanged = function (nodeId) {
var node = this._client.getNode(nodeId),
typeId,
type,
typeName,
executionId,
execution;
if (typeof nodeId === 'string') {
typeId = node.getMetaTypeId();
type = this._client.getNode(typeId);
typeName = type.getAttribute('name');
if (typeName !== 'Job') {
this.logger.error(`Invalid node type for JobEditor: ${typeName}`);
return;
}
executionId = node.getParentId();
execution = this._client.getNode(executionId);
// If the current node is in a snapshotted execution, only show the log
// viewer
if (this.readOnly !== execution.getAttribute('snapshot')) {
this.readOnly = execution.getAttribute('snapshot');
this.logger.info(`readonly set to ${this.readOnly}`);
this.updatePanels();
}
// The OperationCodeEditor should receive the
if (!this.readOnly) {
// Get the operation base node id and pass it to OpCodeEditor selObjChanged
if (this._territoryId) {
this._client.removeUI(this._territoryId);
}
this._territoryId = this._client.addUI(this,
this.onOperationEvents.bind(this));
// Update the territory
this._territory = {};
this._territory[nodeId] = {children: 1};
this._client.updateTerritory(this._territoryId, this._territory);
}
// update the OutputViewer controller
var i = this._panels.length;
this._panels[i-1].control.selectedObjectChanged(nodeId);
}
};
JobEditorPanel.prototype.onOperationEvents = function (events) {
var event = events.find(event => {
if (event.etype === CONSTANTS.TERRITORY_EVENT_LOAD) {
// Check if the eid is an Operation
var typeId = this._client.getNode(event.eid).getMetaTypeId(),
type = this._client.getNode(typeId),
metaBaseId = type && type.getBaseId(),
typeName;
if (metaBaseId) {
typeName = this._client.getNode(metaBaseId).getAttribute('name');
}
return typeName === 'Operation';
}
});
if (event && !this.readOnly) {
var opNode = this._client.getNode(event.eid),
opDefId = opNode.getMetaTypeId();
this._panels[0].control.selectedObjectChanged(opDefId);
this._panels[0].control.offsetNodeChanged(event.eid);
}
};
return JobEditorPanel;
});
@@ -0,0 +1,184 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames'
], function (
CONSTANTS,
GMEConcepts,
nodePropertyNames
) {
'use strict';
var LineGraphControl;
LineGraphControl = 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._currentNodeParentId = undefined;
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).
LineGraphControl.prototype.selectedObjectChanged = function (nodeId) {
var desc = this._getObjectDescriptor(nodeId),
self = this;
self._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
if (self._currentNodeId) {
self._client.removeUI(self._territoryId);
}
self._currentNodeId = nodeId;
self._currentNodeParentId = undefined;
if (typeof self._currentNodeId === 'string') {
// Put new node's info into territory rules
self._selfPatterns = {};
self._selfPatterns[nodeId] = {children: 0}; // Territory "rule"
self._widget.setTitle(desc.name.toUpperCase());
self._currentNodeParentId = desc.parentId;
self._territoryId = self._client.addUI(self, function (events) {
self._eventCallback(events);
});
// Update the territory
self._client.updateTerritory(self._territoryId, self._selfPatterns);
self._selfPatterns[nodeId] = {children: 1};
self._client.updateTerritory(self._territoryId, self._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
LineGraphControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
desc;
if (node) {
desc = {
id: node.getId(),
name: node.getAttribute(nodePropertyNames.Attributes.name)
};
// Check if it is a line
if (desc.id !== this._currentNodeId) {
var points = (node.getAttribute('points') || '').split(';')
.map(pair => {
var nums = pair.split(','),
x = parseFloat(nums[0]),
y = parseFloat(nums[1]);
return {
x: x,
y:y
};
});
desc.type = 'line';
desc.points = points;
}
}
return desc;
};
/* * * * * * * * Node Event Handling * * * * * * * */
LineGraphControl.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');
};
LineGraphControl.prototype._onLoad = function (gmeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.addNode(description);
};
LineGraphControl.prototype._onUpdate = function (gmeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.updateNode(description);
};
LineGraphControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
LineGraphControl.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 * * * * * * * */
LineGraphControl.prototype.destroy = function () {
this._detachClientEventListeners();
};
LineGraphControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this);
};
LineGraphControl.prototype._detachClientEventListeners = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged);
};
LineGraphControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
LineGraphControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return LineGraphControl;
});
@@ -0,0 +1,101 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/LineGraph/LineGraphWidget',
'./LineGraphControl'
], function (
PanelBaseWithHeader,
IActivePanel,
LineGraphWidget,
LineGraphControl
) {
'use strict';
var LineGraphPanel;
LineGraphPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'LineGraphPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(LineGraphPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(LineGraphPanel.prototype, IActivePanel.prototype);
LineGraphPanel.prototype._initialize = function () {
var self = this;
//set Widget title
this.setTitle('');
this.widget = new LineGraphWidget(this.logger, this.$el);
this.widget.setTitle = function (title) {
self.setTitle(title);
};
this.control = new LineGraphControl({
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 */
LineGraphPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
LineGraphPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
LineGraphPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
LineGraphPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
LineGraphPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return LineGraphPanel;
});
@@ -0,0 +1,227 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'blob/BlobClient',
'js/Constants',
'js/Utils/GMEConcepts',
'js/NodePropertyNames',
'deepforge/globals'
], function (
BlobClient,
CONSTANTS,
GMEConcepts,
nodePropertyNames,
DeepForge
) {
'use strict';
var MainViewControl;
MainViewControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this._embedded = options.embedded;
this.territory = {};
this.ui = {};
this._blobClient = new BlobClient({
logger: this._logger.fork('BlobClient')
});
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
MainViewControl.prototype._initWidgetEventHandlers = function () {
this._widget.deleteNode = id => {
var node = this._client.getNode(id),
baseId = node.getBaseId(),
base = this._client.getNode(baseId),
baseName = base.getAttribute('name'),
name = node.getAttribute('name'),
msg = `Deleting ${baseName} "${name}"`;
this._client.startTransaction(msg);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
};
this._widget.dataUrlFor = id => {
var node = this._client.getNode(id),
hash = node.getAttribute('data');
if (hash) {
return this._blobClient.getDownloadURL(hash);
} else {
return null;
}
};
this._widget.toggleEmbeddedPanel = () => this.toggleEmbeddedPanel();
};
/* * * * * * * * 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).
MainViewControl.prototype.selectedObjectChanged = function (nodeId) {
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
this.clearTerritoryRules();
this._currentNodeId = nodeId;
if (typeof this._currentNodeId === 'string') {
var terrTypes = [
/* [type, root dir] */
['arch', 'MyArchitectures'],
['artifact', 'MyArtifacts']
];
terrTypes.forEach(pair => {
var type = pair[0],
dirname = pair[1];
// 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]);
});
}
};
MainViewControl.prototype.handleEvents = function (type, events) {
var event;
// Remove the containing dir
events = events.filter(e => !this.territory[type][e.eid]);
this._logger.debug('_eventCallback \'' + i + '\' items');
for (var i = events.length; i--;) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
this.onLoad(type, event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(type, event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
break;
}
}
this._logger.debug('_eventCallback \'' + events.length + '\' items - DONE');
};
MainViewControl.prototype.onLoad = function(type, id) {
// Load a node of the given type
var desc = this._getObjectDescriptor(type, id);
if (type === 'arch') {
this._widget.addArch(desc);
} else { // artifacts
this._widget.addArtifact(desc);
}
};
// This next function retrieves the relevant node information for the widget
MainViewControl.prototype._getArtifactDesc = function (id) {
var node = this._client.getNode(id),
data = node.getAttribute('data'),
desc = this._getBasicDesc(id);
desc.data = data;
return desc;
};
MainViewControl.prototype._getArchDesc =
MainViewControl.prototype._getBasicDesc = function (id) {
var node = this._client.getNode(id);
return {
id: id,
name: node.getAttribute('name')
};
};
MainViewControl.prototype._getObjectDescriptor = function (type, id) {
return type === 'arch' ?
this._getArchDesc(id) :
this._getArtifactDesc(id);
};
/* * * * * * * * Node Event Handling * * * * * * * */
MainViewControl.prototype._onUpdate = function (type, gmeId) {
var description = this._getObjectDescriptor(type, gmeId);
this._widget.updateNode(description);
};
MainViewControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
MainViewControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId !== activeObjectId) {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
MainViewControl.prototype.destroy = function () {
this._detachClientEventListeners();
this.clearTerritoryRules();
};
MainViewControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged, this);
}
};
MainViewControl.prototype._detachClientEventListeners = function () {
if (!this._embedded) {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
}
};
MainViewControl.prototype.onActivate = function () {
this._attachClientEventListeners();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
MainViewControl.prototype.clearTerritoryRules = function () {
if (Object.keys(this.ui).length) {
Object.keys(this.ui).forEach(id =>
this._client.removeUI(this.ui[id]));
}
};
MainViewControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
};
return MainViewControl;
});
@@ -0,0 +1,161 @@
/*globals define, $, _, WebGMEGlobal*/
/*jshint browser: true*/
// The main panel shows the PipelineIndex w/ a bar on the left for viewing architectures
// and pipelines
define([
'js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/MainView/MainViewWidget',
'./MainViewControl',
'panels/PipelineIndex/PipelineIndexPanel',
'panels/ExecutionIndex/ExecutionIndexPanel',
'deepforge/globals'
], function (
PanelBaseWithHeader,
IActivePanel,
MainViewWidget,
MainViewControl,
PipelineIndexPanel,
ExecutionIndexPanel,
DeepForge
) {
'use strict';
var MainViewPanel;
MainViewPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'MainViewPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this.$nav = $('<div>', {id: 'nav-container'});
this.$el.css({padding: 0});
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');
};
//inherit from PanelBaseWithHeader
_.extend(MainViewPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(MainViewPanel.prototype, IActivePanel.prototype);
MainViewPanel.prototype._initialize = function () {
//set Widget title
this.setTitle('');
this.widget = new MainViewWidget(this.logger, this.$nav);
this.control = new MainViewControl({
logger: this.logger,
client: this._client,
embedded: this._embedded,
widget: this.widget
});
this.control.toggleEmbeddedPanel = this.toggleEmbeddedPanel.bind(this);
var selectedObjectChanged = this.control.selectedObjectChanged;
this.control.selectedObjectChanged = id => {
this.embeddedPanel.control.selectedObjectChanged(this.getEmbeddedNode());
selectedObjectChanged.call(this.control, id);
};
this.toggleEmbeddedPanel(true);
this.onActivate();
};
MainViewPanel.prototype.getEmbeddedNode = function() {
return this.nextPanelIndex === 1 ? DeepForge.places.MyPipelines : 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.embeddedPanel.control.selectedObjectChanged(this.getEmbeddedNode());
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
MainViewPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
MainViewPanel.prototype.onResize = function (width, height) {
var navWidth,
embeddedWidth;
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.widget.onWidgetContainerResize(width, height);
navWidth = this.widget.width();
embeddedWidth = width-navWidth;
this.$embedded.css({
width: embeddedWidth,
height: height,
left: navWidth,
margin: 'inherit'
});
this.embeddedPanel.onResize(embeddedWidth, height);
this.width = width;
this.height = height;
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
MainViewPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
MainViewPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
MainViewPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return MainViewPanel;
});
@@ -1,16 +1,15 @@
/*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([
'panels/TextEditor/TextEditorControl',
'deepforge/viz/OperationControl',
'deepforge/Constants',
'underscore'
], function (
TextEditorControl,
OperationControl,
CONSTANTS,
_
) {
@@ -29,7 +28,11 @@ define([
TextEditorControl.prototype
);
// Override ObjectDescriptor
OperationCodeEditorControl.prototype._initWidgetEventHandlers = function () {
TextEditorControl.prototype._initWidgetEventHandlers.call(this);
this._widget.getOperationAttributes = this.getOperationAttributes.bind(this);
};
OperationCodeEditorControl.prototype.TERRITORY_RULE = {children: 3};
OperationCodeEditorControl.prototype._getObjectDescriptor = function (id) {
var desc = TextEditorControl.prototype._getObjectDescriptor.call(this, id),
@@ -59,5 +62,48 @@ 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;
};
// Line offset handling
OperationCodeEditorControl.prototype.offsetNodeChanged = function (id) {
// Create a territory for this node
if (this._offsetUI) {
this._client.removeUI(this._offsetUI);
}
this._offsetNodeId = id;
this._offsetUI = this._client.addUI(this, this.onOffsetNodeEvents.bind(this));
this._offsetTerritory = {};
this._offsetTerritory[id] = {children: 0};
this._client.updateTerritory(this._offsetUI, this._offsetTerritory);
};
OperationCodeEditorControl.prototype.onOffsetNodeEvents = function () {
var node = this._client.getNode(this._offsetNodeId);
if (node) { // wasn't a 'delete' event
this._widget.setLineOffset(node.getAttribute(CONSTANTS.LINE_OFFSET) || 0);
}
};
OperationCodeEditorControl.prototype.destroy = function () {
TextEditorControl.prototype.destroy.call(this);
if (this._offsetUI) {
this._client.removeUI(this._offsetUI);
}
};
return OperationCodeEditorControl;
});
@@ -1,8 +1,5 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 12:00:46 GMT-0500 (CDT).
*/
define([
'js/PanelBase/PanelBaseWithHeader',
@@ -1,15 +1,21 @@
/*globals define, */
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'deepforge/globals',
'deepforge/viz/RenameablePanel',
'panels/TilingViz/TilingVizPanel',
'panels/OperationCodeEditor/OperationCodeEditorPanel',
'panels/OperationInterfaceEditor/OperationInterfaceEditorPanel',
'js/Constants',
'underscore'
], function (
DeepForge,
RenameablePanel,
TilingViz,
CodeEditor,
InterfaceEditor,
CONSTANTS,
_
) {
'use strict';
@@ -18,13 +24,66 @@ define([
OperationEditorPanel = function (layoutManager, params) {
TilingViz.call(this, layoutManager, params);
this.initialize();
};
OperationEditorPanel.prototype.initialize = function () {
this.territory = {};
this.territoryId = null;
this._currentNodeId = null;
this.control = this;
// Set the editable title on node change
this.initializeRenameable();
};
//inherit from TilingViz
_.extend(OperationEditorPanel.prototype, TilingViz.prototype);
_.extend(
OperationEditorPanel.prototype,
RenameablePanel.prototype,
TilingViz.prototype
);
OperationEditorPanel.prototype.selectedObjectChanged = function (id) {
this._currentNodeId = id;
DeepForge.last.Operation = id;
if (typeof this._currentNodeId === 'string') {
// Setup the territory
this.territory = {};
this.territory[this._currentNodeId] = {children: 0};
this.territoryId = this._client.addUI(this, this._eventCallback.bind(this));
this._client.updateTerritory(this.territoryId, this.territory);
}
TilingViz.prototype.selectedObjectChanged.call(this, id);
};
OperationEditorPanel.prototype._eventCallback = function (events) {
events = events.find(e => e.eid === this._currentNodeId);
this.updateTitle();
};
OperationEditorPanel.prototype.updateTitle = function () {
var id = this._currentNodeId,
node = this._client.getNode(id),
name = node && node.getAttribute('name');
this.setTitle(name || '');
};
OperationEditorPanel.prototype.getPanels = function () {
return [CodeEditor, InterfaceEditor];
return [InterfaceEditor, CodeEditor];
};
OperationEditorPanel.prototype.onDeactivate = function () {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT,
this._stateActiveObjectChanged);
if (this.territoryId) {
this._client.removeUI(this.territoryId);
}
TilingViz.prototype.onDeactivate.call(this);
};
return OperationEditorPanel;
@@ -0,0 +1,5 @@
/*globals define*/
define({
PRIMITIVE: '#b0bec5',
COMPLEX: '#78909c'
});
@@ -1,6 +1,8 @@
/*globals define*/
define([
'./Colors'
], function(
COLORS
) {
'use strict';
var OperationInterfaceEditorEvents = function() {
@@ -9,6 +11,25 @@ define([
this._widget.addRefTo = this.addRefTo.bind(this);
this._widget.changePtrName = this.changePtrName.bind(this);
this._widget.removePtr = this.removePtr.bind(this);
this._widget.getCreationNode = this.getCreationNode.bind(this);
};
OperationInterfaceEditorEvents.prototype.getCreationNode = function(type, id) {
var typeName = type === 'Complex' ? 'Class' : 'Primitive',
Decorator = this._client.decoratorManager.getDecoratorForWidget(
this.DEFAULT_DECORATOR, 'EasyDAG');
return {
node: {
id: id,
class: 'create-node',
name: `New ${typeName}...`,
Decorator: Decorator,
color: COLORS[type.toUpperCase()],
isPrimitive: type === 'Primitive',
attributes: {}
}
};
};
OperationInterfaceEditorEvents.prototype.allValidReferences = function() {
@@ -19,7 +40,7 @@ define([
var notTypes = ['Data', 'Operation', 'Pipeline'];
return this._client.getAllMetaNodes()
.filter(node => {
var plugins = node.getRegistry('validPlugins');
var plugins = node.getOwnRegistry('validPlugins');
// Convention is enforced; if the plugin generates lua artifacts,
// it should be called `Generate`.. (something)
return plugins && plugins.indexOf('Generate') !== -1;
@@ -34,23 +55,28 @@ define([
});
};
OperationInterfaceEditorEvents.prototype.allDataTypeIds = function() {
return this.allDataTypes().map(node => node.getId());
OperationInterfaceEditorEvents.prototype.allDataTypeIds = function(incAbstract) {
return this.allDataTypes(incAbstract).map(node => node.getId());
};
OperationInterfaceEditorEvents.prototype.allDataTypes = function() {
OperationInterfaceEditorEvents.prototype.allDataTypes = function(incAbstract) {
return this._client.getAllMetaNodes()
.filter(node => this.hasMetaName(node.getId(), 'Data'))
.filter(node => this.hasMetaName(node.getId(), 'Data', incAbstract))
.filter(node => !node.isAbstract());
};
OperationInterfaceEditorEvents.prototype._getValidSuccessorNodes = function(nodeId) {
// Return all data types in the meta
OperationInterfaceEditorEvents.prototype.getValidSuccessors = function(nodeId, isInput) {
var dataTypeIds;
if (nodeId !== this._currentNodeId) {
return [];
}
return this.allDataTypeIds().map(id => {
// Return all data types in the meta
// If input, include abstract types
dataTypeIds = this.allDataTypeIds(isInput);
return dataTypeIds.map(id => {
return {
node: this._getObjectDescriptor(id)
};
@@ -9,14 +9,20 @@
define([
'panels/EasyDAG/EasyDAGControl',
'js/Constants',
'deepforge/Constants',
'deepforge/lua',
'deepforge/viz/OperationControl',
'./OperationInterfaceEditorControl.EventHandlers',
'./Colors',
'underscore'
], function (
EasyDAGControl,
GME_CONSTANTS,
CONSTANTS,
luajs,
OperationControl,
OperationInterfaceEditorControlEvents,
COLORS,
_
) {
@@ -30,6 +36,9 @@ define([
OperationInterfaceEditorControlEvents.call(this);
this._connections = {};
this._pointers = {};
this._usage = {}; // info about input usage
this._inputs = {};
};
_.extend(
@@ -81,13 +90,13 @@ define([
for (var i = 0; i < events.length; i++) {
event = events[i];
switch (event.etype) {
case CONSTANTS.TERRITORY_EVENT_LOAD:
case GME_CONSTANTS.TERRITORY_EVENT_LOAD:
this._onLoad(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UPDATE:
case GME_CONSTANTS.TERRITORY_EVENT_UPDATE:
this._onUpdate(event.eid);
break;
case CONSTANTS.TERRITORY_EVENT_UNLOAD:
case GME_CONSTANTS.TERRITORY_EVENT_UNLOAD:
this._onUnload(event.eid);
break;
default:
@@ -139,18 +148,48 @@ define([
desc.container = cntr.toLowerCase();
desc.attributes = {};
} else if (desc.id === this._currentNodeId) {
desc.pointers = {};
// Remove DeepForge hidden attributes
delete desc.attributes.code;
delete desc.attributes[CONSTANTS.LINE_OFFSET];
}
// Extra decoration for data
if (this.hasMetaName(desc.id, 'Data', true)) {
desc.color = this.getDescColor(gmeId);
desc.isPrimitive = this.hasMetaName(gmeId, 'Primitive');
var used = desc.container === 'inputs' ?
this.isUsedInput(desc.name) : this.isUsedOutput(desc.name);
if (used !== null) {
desc.used = used;
this._usage[desc.id] = desc.used;
} else {
desc.used = this._usage[desc.id] !== undefined ?
this._usage[desc.id] : true;
}
this._inputs[desc.id] = desc.container === 'inputs';
}
return desc;
};
OperationInterfaceEditorControl.prototype.getDescColor = function(gmeId) {
return !this.hasMetaName(gmeId, 'Primitive', true) ? COLORS.COMPLEX :
COLORS.PRIMITIVE;
};
OperationInterfaceEditorControl.prototype._onUnload = function(gmeId) {
EasyDAGControl.prototype._onUnload.call(this, gmeId);
var conn = this._connections[gmeId];
if (conn) {
this._widget.removeNode(conn.id);
}
delete this._usage[gmeId];
delete this._inputs[gmeId];
};
OperationInterfaceEditorControl.prototype._onLoad = function(gmeId) {
@@ -170,12 +209,40 @@ define([
};
OperationInterfaceEditorControl.prototype._onUpdate = function(gmeId) {
var variableIds,
wasUsed,
isUsed,
name,
ast,
code;
if (gmeId === this._currentNodeId) {
EasyDAGControl.prototype._onUpdate.call(this, gmeId);
// Update the valid pointers
this.updatePtrs();
// Update the remaining usage info
variableIds = Object.keys(this._usage);
code = this._client.getNode(this._currentNodeId).getAttribute('code');
try {
ast = luajs.parser.parse(code);
for (var i = variableIds.length; i--;) {
wasUsed = this._usage[variableIds[i]];
name = this._client.getNode(variableIds[i]).getAttribute('name');
isUsed = this._inputs[variableIds[i]] ?
this.isUsedInput(name, ast) :
this.isUsedOutput(name, ast);
if (isUsed !== wasUsed) {
this._onUpdate(variableIds[i]);
}
}
} catch (e) {
this._logger.debug(`failed parsing lua: ${e}`);
}
} else if (this.containedInCurrent(gmeId) && this.hasMetaName(gmeId, 'Data')) {
EasyDAGControl.prototype._onUpdate.call(this, gmeId);
}
@@ -192,13 +259,20 @@ define([
.items[0].id,
target = this._client.getNode(targetId),
decManager = this._client.decoratorManager,
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG');
Decorator = decManager.getDecoratorForWidget('OpIntPtrDecorator', 'EasyDAG'),
id = 'ptr_'+name,
used = this.isUsedInput(name);
if (used === null) {
used = this._usage[id] !== undefined ? this._usage[id] : true;
}
return {
id: 'ptr_'+name,
id: id,
isPointer: true,
baseName: target.getAttribute('name'),
Decorator: Decorator,
used: used,
attributes: {},
name: name,
parentId: this._currentNodeId
@@ -217,7 +291,7 @@ define([
// Get the pointers that should exist [name, target]
this.loadMeta();
newPtrs = node.getPointerNames()
.filter(name => name !== CONSTANTS.POINTER_BASE)
.filter(name => name !== GME_CONSTANTS.POINTER_BASE)
.map(name => this.getPtrDescriptor(name));
// Compare them to the existing...
@@ -255,9 +329,13 @@ define([
OperationInterfaceEditorControl.prototype.rmPtr = function(id) {
// Remove the pointer's node
this._widget.removeNode(id);
// and connection
var conn = this._connections[id];
this._widget.removeNode(conn.id);
// and usage info
delete this._usage[id];
};
OperationInterfaceEditorControl.prototype.containedInCurrent = function(id) {
@@ -282,5 +360,79 @@ define([
return conn;
};
////////////////////// Unused input checking //////////////////////
OperationInterfaceEditorControl.prototype.isUsedInput = function(name, ast) {
return this._isUsed(name, true, ast);
};
OperationInterfaceEditorControl.prototype.isUsedOutput = function(name, ast) {
return this._isUsed(name, false, ast);
};
OperationInterfaceEditorControl.prototype._isUsed = function(name, isInput, ast) {
var code = this._client.getNode(this._currentNodeId).getAttribute('code'),
r = new RegExp('\\b' + name + '\\b'),
hasText = code.match(r) !== null;
// verify that it is not used only in the left side of an assignment
if (hasText) {
try {
ast = ast || luajs.parser.parse(code);
return isInput ? this.isUsedVariable(name, ast) : this.isReturnValue(name, ast);
} catch(e) {
this._logger.debug(`failed parsing lua: ${e}`);
return null;
}
}
return false;
};
// Check if it is used in the given ast node
OperationInterfaceEditorControl.prototype.isUsedVariable = function(name, node) {
var isUsed = false,
checker;
checker = luajs.codegen.traverse((curr, parent) => {
if (curr.type === 'variable' && curr.val === name) {
// Ignore if it is being assigned...
if (parent.type === 'stat.assignment') {
isUsed = isUsed || parent.right.indexOf(curr) !== -1;
} else {
isUsed = true;
}
}
return curr;
});
checker(node);
return isUsed;
};
OperationInterfaceEditorControl.prototype.isReturnValue = function(name, ast) {
var firstReturn,
fields,
key,
node;
for (var i = ast.block.stats.length; i--;) {
node = ast.block.stats[i];
if (node.type === 'stat.return') {
// Check that it returns an object w/ a key of the given name
firstReturn = node.nret[0];
if (firstReturn && firstReturn.type === 'expr.constructor') {
fields = firstReturn.fields;
for (var j = fields.length; j--;) {
key = fields[j].key;
if (key.type === 'const.string' && key.val === name) {
return true;
}
}
}
}
}
return false;
};
return OperationInterfaceEditorControl;
});
@@ -0,0 +1,13 @@
.output-viewer .output-pager {
position: absolute;
left: 0.75em;
bottom: 0;
z-index: 100;
}
.output-viewer .empty {
visibility: hidden;
}
.output-viewer .pagination {
margin-bottom: 0.5em;
}
@@ -0,0 +1,322 @@
/*globals define, $, _, WebGMEGlobal*/
/*jshint browser: true*/
// The OutputViewer is a viz which shows the LogViewer and, if the job has
// 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',
'js/Constants',
'js/RegistryKeys',
'text!api/visualizers',
'css!./OutputViewer.css'
], function (
IconTxt,
PanelBaseWithHeader,
IActivePanel,
LogViewer,
CONSTANTS,
REGISTRY_KEYS,
VisualizersJSON
) {
'use strict';
var OutputViewerPanel,
Visualizers = JSON.parse(VisualizersJSON),
IconFor = JSON.parse(IconTxt);
OutputViewerPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'OutputViewerPanel';
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._currentNodeId = null;
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._layoutManager = layoutManager;
this.dimensions = null;
this._params = params;
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(OutputViewerPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(OutputViewerPanel.prototype, IActivePanel.prototype);
OutputViewerPanel.prototype._initialize = function () {
this.control = this; // implement selectedObjectChanged here
this._panels = {
LogViewer: LogViewer
};
// Create the pagination container
this._pages = {};
this._pageCount = 0;
this.$el.addClass('output-viewer');
this.$pager = $('<nav>', {class: 'output-pager empty'});
this.$pagerList = $('<ul>', {class: 'pagination'});
// Add the console item
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);
this.$pager.append(this.$pagerList);
this.$el.append(this.$pager);
this.$el.css({padding: 0});
// On 'page' clicked, set the activePanel to a new AutoViz and set
// the given nodeId as the active node for it
this.$pager.on('click', 'li', event => {
var element = $(event.target);
this.selectOutput(element);
});
// Set the activePanel
this.activePanel = new LogViewer(this._layoutManager, this._params);
this.$el.append(this.activePanel.$el);
this.onActivate();
};
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;
if (dataId) {
this.loadOutputFor(dataId);
} else { // Set the logviewer
this.loadPanel(LogViewer, this._currentNodeId);
}
}
};
OutputViewerPanel.prototype.loadOutputFor = function (id) {
var node = this._client.getNode(id),
panelId,
panel,
panelPath;
if (!node) {
this.logger.error(`could not load node: ${id}`);
return;
}
// Get the registered visualizer
panelId = (node.getRegistry(REGISTRY_KEYS.VALID_VISUALIZERS) || '')
.split(' ')
.shift();
// Load it (embedded) and set the selected node to 'id'
panel= Visualizers.find(desc => desc.id === panelId);
if (panel) {
panelPath = panel.panel;
if (this._panels[panelPath]) {
this.loadPanel(this._panels[panelPath], id);
} else {
require([panelPath],
function(Panel) {
this._panels[panelPath] = Panel;
this.loadPanel(Panel, id);
}.bind(this),
err =>
this.logger.error(`could not load ${panelPath}: ${err}`)
);
}
} else {
this.logger.warn(`Could not find visualizer: ${panelId}`);
}
};
OutputViewerPanel.prototype.loadPanel = function (Panel, nodeId) {
if (this.activePanel) {
this.activePanel.destroy();
this.activePanel.$el.remove();
}
this.activePanel = new Panel(this._layoutManager, this._params);
this.$el.append(this.activePanel.$el);
if (nodeId) {
this.activePanel.control.selectedObjectChanged(nodeId);
}
if (this.dimensions) {
this.onResize.apply(this, this.dimensions);
}
};
OutputViewerPanel.prototype.clearTerritory = function () {
if (this._territoryUI) {
this._client.removeUI(this._territoryUI);
this._territoryUI = null;
}
};
OutputViewerPanel.prototype.selectedObjectChanged = function (nodeId) {
if (typeof nodeId === 'string') {
this._currentNodeId = nodeId;
this.clearTerritory();
this._territoryUI = this._client.addUI(this, this.handleEvents.bind(this));
// Create the territory (active node and children)
this._territory = {};
this._territory[nodeId] = {children: 1};
this._client.updateTerritory(this._territoryUI, this._territory);
this.activePanel.control.selectedObjectChanged(nodeId);
}
};
OutputViewerPanel.prototype.getMetadataId = function () {
var metanodes = this._client.getAllMetaNodes();
for (var i = metanodes.length; i--;) {
if (metanodes[i].getAttribute('name') === 'Metadata') {
return metanodes[i].getId();
}
}
return null;
};
OutputViewerPanel.prototype.handleEvents = function (events) {
var metadataId = this.getMetadataId(),
event;
if (!metadataId) {
this.logger.error(`No metadata id found! "${metadataId}"`);
return;
}
events = events.filter(event => event.eid && (this._pages[event.eid] ||
this._client.isTypeOf(event.eid, metadataId)));
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;
}
}
};
OutputViewerPanel.prototype.onUpdate = function (nodeId) {
if (this._pages[nodeId]) {
this.updatePage(nodeId);
}
};
OutputViewerPanel.prototype.onLoad = function (nodeId) {
var node = this._client.getNode(nodeId),
name = node.getAttribute('name');
this.addToPager(name, nodeId);
};
OutputViewerPanel.prototype.onUnload = function (nodeId) {
// If the current metadata node is deleted, change back to logviewer
if (this._pages[nodeId]) {
var selectedId = this.$selected.data('id');
if (nodeId === selectedId) {
this.selectOutput(this.$logviewer);
}
// Update the pager
this._pages[nodeId].remove();
this._pageCount--;
if (this._pageCount === 0) {
this.$pager.addClass('empty');
}
}
};
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.attr('data-id', nodeId);
$el.append($a);
this._pages[nodeId] = $el;
this.updatePage(nodeId);
this.$pager.removeClass('empty');
this.$pagerList.append($el);
this._pageCount++;
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
OutputViewerPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
OutputViewerPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
this.dimensions = arguments;
this.$el.css({
width: width,
height: height
});
this.activePanel.onResize(width, height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
OutputViewerPanel.prototype.destroy = function () {
this.activePanel.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
OutputViewerPanel.prototype.onActivate = function () {
this.activePanel.onActivate();
};
OutputViewerPanel.prototype.onDeactivate = function () {
this.activePanel.onDeactivate();
};
return OutputViewerPanel;
});
@@ -0,0 +1,5 @@
{
"Image": "picture",
"Console": "console",
"Graph": "random"
}
@@ -5,6 +5,7 @@ define([
'js/Constants',
'panels/EasyDAG/EasyDAGControl',
'deepforge/viz/PipelineControl',
'deepforge/globals',
'common/core/coreQ',
'common/storage/constants',
'q',
@@ -13,6 +14,7 @@ define([
CONSTANTS,
EasyDAGControl,
PipelineControl,
DeepForge,
Core,
STORAGE_CONSTANTS,
Q,
@@ -37,6 +39,7 @@ define([
this.addedIds = {};
this.executionTerritory = {};
this.executionUI = null;
this.invalidated = {};
this._widget.deleteNode = id => {
this._deleteNode(id);
};
@@ -53,6 +56,7 @@ define([
PipelineEditorControl.prototype.TERRITORY_RULE = {children: 3};
PipelineEditorControl.prototype.selectedObjectChanged = function (nodeId) {
DeepForge.last.Pipeline = nodeId;
this._logger.debug('activeObject nodeId \'' + nodeId + '\'');
// Remove current territory patterns
@@ -65,7 +69,7 @@ define([
if (typeof this._currentNodeId === 'string') {
var desc = this._getObjectDescriptor(nodeId);
this._widget.setTitle(desc.name.toUpperCase());
this._widget.setTitle(desc.name);
if (typeof desc.parentId === 'string') {
this.$btnModelHierarchyUp.show();
@@ -80,6 +84,19 @@ define([
}
};
PipelineEditorControl.prototype.hasCurrentNode = function () {
return typeof this._currentNodeId === 'string';
};
PipelineEditorControl.prototype.onNodeNameChanged = function (from, to) {
var msg = `Renaming pipeline "${from}" -> "${to}"`;
if (from !== to && !/^\s*$/.test(to)) {
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, 'name', to);
this._client.completeTransaction();
}
};
PipelineEditorControl.prototype.updateTerritory = function() {
var nodeId = this._currentNodeId;
@@ -119,6 +136,8 @@ define([
this._widget.getExistingPortMatches = this.getExistingPortMatches.bind(this);
this._widget.createConnection = this.createConnection.bind(this);
this._widget.removeConnection = this.removeConnection.bind(this);
this._widget.getDecorator = this.getDecorator.bind(this);
this._widget.updateThumbnail = this.updateThumbnail.bind(this);
};
PipelineEditorControl.prototype.isContainedInActive = function (gmeId) {
@@ -132,7 +151,10 @@ define([
var desc = this._getObjectDescriptor(gmeId);
if (desc.parentId === this._currentNodeId) {
this.addedIds[desc.id] = true;
return EasyDAGControl.prototype._onLoad.call(this, gmeId);
// Validate any connections
if (this.isValid(desc)) {
return EasyDAGControl.prototype._onLoad.call(this, gmeId);
}
} else if (desc.parentId !== null &&
this.isContainedInActive(desc.parentId) && desc.isDataPort) {
// port added!
@@ -141,8 +163,33 @@ define([
}
};
PipelineEditorControl.prototype.isValid = function (desc) {
// If it is a "dangling connection", remove it!
if (desc.isConnection) {
if (!(desc.src && desc.dst)) {
var node = this._client.getNode(this._currentNodeId),
name = node.getAttribute('name'),
msg = `Removing invalid connection ${desc.id} in "${name}"`;
this.invalidated[desc.id] = true;
this._client.startTransaction(msg);
this._client.delMoreNodes([desc.id]);
this._client.completeTransaction();
return false;
}
}
return true;
};
PipelineEditorControl.prototype._onUnload = function (gmeId) {
// Check if it has been added
if (this.invalidated[gmeId]) {
// No need to notify the widget; this was filtered bc it was
// an invalid connection
delete this.invalidated[gmeId];
return;
}
if(this.addedIds[gmeId]) {
delete this.addedIds[gmeId];
return EasyDAGControl.prototype._onUnload.call(this, gmeId);
@@ -537,5 +584,65 @@ define([
EasyDAGControl.prototype._detachClientEventListeners.call(this);
};
////////////////////// Execution Support END //////////////////////
PipelineEditorControl.prototype.getDecorator = function (nodeId) {
var node = this._client.getNode(nodeId);
if (node) {
return this._getNodeDecorator(node);
} else {
return this._client.decoratorManager.getDecoratorForWidget(
this.DEFAULT_DECORATOR, WIDGET_NAME);
}
};
PipelineEditorControl.prototype.updateThumbnail = function (svg) {
var node = this._client.getNode(this._currentNodeId),
name,
attrs,
currentThumbnail,
attrName = 'thumbnail',
msg;
if (node) { // may have been deleted
name = node.getAttribute('name');
attrs = node.getValidAttributeNames();
currentThumbnail = node.getAttribute(attrName);
msg = `Updating pipeline thumbnail for "${name}"`;
if (attrs.indexOf(attrName) > -1 && currentThumbnail !== svg) {
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, attrName, svg);
this._client.completeTransaction();
}
}
};
////////////////////// Criterion Support //////////////////////
PipelineEditorControl.prototype._getValidTargetsFor = function (id, ptr) {
// Check if the pointer is a Criterion pointer -> if so, only show the meta types
// and the ones in the custom layer dir
var typeIds = this._client.getPointerMeta(id, ptr).items.map(item => item.id),
types = typeIds.map(id => this._client.getNode(id)),
criterion = types.find(node => node.getAttribute('name') === 'Criterion'),
items,
criterionId;
if (criterion) {
// Get all criterion types
criterionId = criterion.getId();
items = this._client.getAllMetaNodes().map(node => node.getId())
.filter(id => this._client.isTypeOf(id, criterionId));
return items.map(id => {
return {
node: this._getObjectDescriptor(id)
};
});
} else {
return EasyDAGControl.prototype._getValidTargetsFor.apply(this, arguments);
}
};
return PipelineEditorControl;
});
@@ -61,9 +61,25 @@ define(['js/PanelBase/PanelBaseWithHeader',
widget: this.widget
});
// Editable pipeline name
this.$panelHeaderTitle.on('dblclick', () => this.editTitle());
this.onActivate();
};
PipelineEditorPanel.prototype.editTitle = function () {
if (this.control.hasCurrentNode()) {
this.$panelHeaderTitle.editInPlace({
css: {
'z-index': 1000
},
onChange: (oldValue, newValue) => {
this.control.onNodeNameChanged(oldValue, newValue);
}
});
}
};
/* OVERRIDE FROM WIDGET-WITH-HEADER */
/* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
PipelineEditorPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
@@ -0,0 +1,225 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
define([
'js/Constants',
'js/NodePropertyNames'
], function (
CONSTANTS,
nodePropertyNames
) {
'use strict';
var PipelineIndexControl;
PipelineIndexControl = function (options) {
this._logger = options.logger.fork('Control');
this._client = options.client;
// Initialize core collections and variables
this._widget = options.widget;
this._currentNodeId = null;
this._embedded = options.embedded;
this._initWidgetEventHandlers();
this._logger.debug('ctor finished');
};
PipelineIndexControl.prototype._initWidgetEventHandlers = function () {
this._widget.deletePipeline = id => {
var node = this._client.getNode(id),
name = node.getAttribute('name'),
msg = `Deleting pipeline "${name}"`;
// Change the current active object
this._client.startTransaction(msg);
this._client.delMoreNodes([id]);
this._client.completeTransaction();
};
this._widget.setName = (id, name) => {
var oldName = this._client.getNode(id).getAttribute('name'),
msg = `Renaming Pipeline: "${oldName}" -> "${name}"`;
if (oldName !== name && !/^\s*$/.test(name)) {
this._client.startTransaction(msg);
this._client.setAttributes(id, 'name', name);
this._client.completeTransaction();
}
};
};
/* * * * * * * * 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).
PipelineIndexControl.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: 1};
this._territoryId = this._client.addUI(this, this._eventCallback.bind(this));
// Update the territory
this._client.updateTerritory(this._territoryId, this._selfPatterns);
}
};
// This next function retrieves the relevant node information for the widget
PipelineIndexControl.prototype._getObjectDescriptor = function (nodeId) {
var node = this._client.getNode(nodeId),
objDescriptor;
if (node) {
objDescriptor = {
id: undefined,
name: undefined,
parentId: undefined,
thumbnail: node.getAttribute('thumbnail'),
executionCount: node.getMemberIds('executions').length
};
objDescriptor.id = node.getId();
objDescriptor.name = node.getAttribute(nodePropertyNames.Attributes.name);
objDescriptor.parentId = node.getParentId();
}
return objDescriptor;
};
/* * * * * * * * Node Event Handling * * * * * * * */
PipelineIndexControl.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');
};
PipelineIndexControl.prototype._onLoad = function (gmeId) {
if (gmeId !== this._currentNodeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.addNode(description);
}
};
PipelineIndexControl.prototype._onUpdate = function (gmeId) {
if (gmeId !== this._currentNodeId) {
var description = this._getObjectDescriptor(gmeId);
this._widget.updateNode(description);
}
};
PipelineIndexControl.prototype._onUnload = function (gmeId) {
this._widget.removeNode(gmeId);
};
PipelineIndexControl.prototype._stateActiveObjectChanged = function (model, activeObjectId) {
if (this._currentNodeId !== activeObjectId) {
this.selectedObjectChanged(activeObjectId);
}
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
PipelineIndexControl.prototype.destroy = function () {
this._detachClientEventListeners();
this._removeToolbarItems();
};
PipelineIndexControl.prototype._attachClientEventListeners = function () {
this._detachClientEventListeners();
if (!this._embedded) {
WebGMEGlobal.State.on('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged, this);
}
};
PipelineIndexControl.prototype._detachClientEventListeners = function () {
if (!this._embedded) {
WebGMEGlobal.State.off('change:' + CONSTANTS.STATE_ACTIVE_OBJECT, this._stateActiveObjectChanged);
}
};
PipelineIndexControl.prototype.onActivate = function () {
this._attachClientEventListeners();
this._displayToolbarItems();
if (typeof this._currentNodeId === 'string') {
WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
WebGMEGlobal.State.registerActiveObject(this._currentNodeId);
WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
}
};
PipelineIndexControl.prototype.onDeactivate = function () {
this._detachClientEventListeners();
this._hideToolbarItems();
};
/* * * * * * * * * * Updating the toolbar * * * * * * * * * */
PipelineIndexControl.prototype._displayToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].show();
}
} else {
this._initializeToolbar();
}
};
PipelineIndexControl.prototype._hideToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].hide();
}
}
};
PipelineIndexControl.prototype._removeToolbarItems = function () {
if (this._toolbarInitialized === true) {
for (var i = this._toolbarItems.length; i--;) {
this._toolbarItems[i].destroy();
}
}
};
PipelineIndexControl.prototype._initializeToolbar = function () {
this._toolbarItems = [];
this._toolbarInitialized = true;
};
return PipelineIndexControl;
});
@@ -0,0 +1,94 @@
/*globals define, _, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed Jun 29 2016 16:10:46 GMT-0500 (CDT).
*/
define(['js/PanelBase/PanelBaseWithHeader',
'js/PanelManager/IActivePanel',
'widgets/PipelineIndex/PipelineIndexWidget',
'./PipelineIndexControl'
], function (PanelBaseWithHeader,
IActivePanel,
PipelineIndexWidget,
PipelineIndexControl) {
'use strict';
var PipelineIndexPanel;
PipelineIndexPanel = function (layoutManager, params) {
var options = {};
//set properties from options
options[PanelBaseWithHeader.OPTIONS.LOGGER_INSTANCE_NAME] = 'PipelineIndexPanel';
options[PanelBaseWithHeader.OPTIONS.FLOATING_TITLE] = true;
//call parent's constructor
PanelBaseWithHeader.apply(this, [options, layoutManager]);
this._client = params.client;
this._embedded = params.embedded;
//initialize UI
this._initialize();
this.logger.debug('ctor finished');
};
//inherit from PanelBaseWithHeader
_.extend(PipelineIndexPanel.prototype, PanelBaseWithHeader.prototype);
_.extend(PipelineIndexPanel.prototype, IActivePanel.prototype);
PipelineIndexPanel.prototype._initialize = function () {
//set Widget title
this.setTitle('');
this.widget = new PipelineIndexWidget(this.logger, this.$el);
this.control = new PipelineIndexControl({
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 */
PipelineIndexPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
//apply parent's onReadOnlyChanged
PanelBaseWithHeader.prototype.onReadOnlyChanged.call(this, isReadOnly);
};
PipelineIndexPanel.prototype.onResize = function (width, height) {
this.logger.debug('onResize --> width: ' + width + ', height: ' + height);
};
/* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
PipelineIndexPanel.prototype.destroy = function () {
this.control.destroy();
this.widget.destroy();
PanelBaseWithHeader.prototype.destroy.call(this);
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
PipelineIndexPanel.prototype.onActivate = function () {
this.widget.onActivate();
this.control.onActivate();
WebGMEGlobal.KeyboardManager.setListener(this.widget);
WebGMEGlobal.Toolbar.refresh();
};
PipelineIndexPanel.prototype.onDeactivate = function () {
this.widget.onDeactivate();
this.control.onDeactivate();
WebGMEGlobal.KeyboardManager.setListener(undefined);
WebGMEGlobal.Toolbar.refresh();
};
return PipelineIndexPanel;
});
@@ -16,6 +16,7 @@ define([
SerializeEditorControl = function (options) {
options.attributeName = 'serialize';
TextEditorControl.call(this, options);
this._widget.setName = this.setName.bind(this);
};
_.extend(
@@ -1,8 +1,5 @@
/*globals define, WebGMEGlobal*/
/*jshint browser: true*/
/**
* Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 08:58:20 GMT-0500 (CDT).
*/
define([
'js/Constants',
@@ -47,12 +44,23 @@ define([
`for ${id} - node doesn't have the given attribute!`);
}
};
this._widget.setName = this.setName.bind(this);
};
TextEditorControl.prototype.saveTextFor = function (id, text) {
this._client.setAttributes(id, this.ATTRIBUTE_NAME, text);
};
TextEditorControl.prototype.setName = function (name) {
var node = this._client.getNode(this._currentNodeId),
oldName = node.getAttribute('name'),
msg = `Renaming ${oldName} -> ${name}`;
this._client.startTransaction(msg);
this._client.setAttributes(this._currentNodeId, 'name', name);
this._client.completeTransaction();
};
TextEditorControl.prototype.TERRITORY_RULE = {children: 0};
TextEditorControl.prototype.selectedObjectChanged = function (nodeId) {
var self = this;
@@ -178,6 +186,10 @@ define([
TextEditorControl.prototype.destroy = function () {
this._detachClientEventListeners();
this._removeToolbarItems();
if (this._territoryId) {
this._client.removeUI(this._territoryId);
}
};
TextEditorControl.prototype._attachClientEventListeners = function () {

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